Полгода назад решил написать online-приложение «Карта звёздного неба». Думаю, многие из нас когда-либо видели эту самую карту звёздного неба, и вероятно, она привлекала к себе внимание.
Я подумал, что интересно будет осуществить нечто подобное на JS. Было решено отчасти использовать готовую библиотеку LibCanvas из-за её продуманного синтаксиса, что было важно при написании объёмных приложений.
Первая проблема, с которой я столкнулся — это довольно большое количество звёзд, которое требуется отобразить с высокой точностью — их около 6 000. Здесь я решил при помощи несложного PHP-скрипта сгенерировать из текстового файла каталога звёзд массив для js.
Когда использовать LibCanvas?
Собственно стал вопрос; стоит ли всегда использовать LibCanvas? Дело в том, что в проекте кроме самой карты, должен отрисовываться коллаж видимых размеров планет, который предполагал написание отдельной библиотеки и для этой задачи я решил не использовать LibCanvas.
Библиотека математических и астрономических функций
Проект требовал многократного использования разных математических функций, поэтому решено было написать библиотеку этих самых функций.
Собственно, вот результат.
Там соответсвенно:
- Тригонометрические функции с градусным аргументом
- Функции преобразования юлианского дня в григорианскую дату
- Функции перевода горизонтальных/экваториальных координат
- Вычисление атмосферной рефракции
- Прочие (названия месяцев, получение текущего времени и т.д.)
Каталоги данных
База данных объектов в основном находиться здесь
Так же здесь находятся элементы орбит планет и комет.
Отображение звёздочек
for (var i = 0; i < (stars.length); i++){
var decr=stars[i][1]; //Склонение
var tr=sr-stars[i][0]; //Прямое восхождение
var zl=atmospheric_refraction(equatorial_to_horizontal(decr, tr, phi)[1]);//Зенитное расстояние
var mag=Math.round(stars[i][2]/100); //Магнитуда
if (zl<90 && mag<magmax){//Все звезды, которые выше горизонта
var r_star=k1*1+k2*(magmax-mag);
var Az=equatorial_to_horizontal(decr, tr, phi)[0]; //Азимут
var cor1=to_xy(zl,Az); Функция рассчета положения звезды
var x=(cor1[0]*1).toFixed(0); //Абцисс координата
var y=(cor1[1]*1).toFixed(0); //Ординат
/* У ярких звёздочек рисуем гало */
if (mag<1.5){
var circl3 = new LC.Circle( x,y,r_star*2);
ct.fill(circl3, ct
.createRadialGradient(
new LC.Circle(x, y, 1),
new LC.Circle(x, y, r_star*2))
.addColorStop({
'0.0': 'rgba(200,200,200,0.4)',
'1.0': 'rgba(200,200,200,0)'
}));
var circl = new LC.Circle( x,y,r_star*0.8); //Рисуем круг
ct.fill(circl, '#FFF');//Белый круг
}else{
/* У тусклых звёздочек рисуем просто круг */
var circl = new LC.Circle( x,y,r_star); //Рисуем круг
ct.fill(circl, '#FFF');//Белый круг
}
m++;
}
}
Планеты
Отображения на карте
Я решил выделить планеты жёлтым цветом ( подстраиваюсь под реальность). Для вычисления положений планет и написал библиотеку
Отображения в коллаже
Тут тоже пришлось немного поработать, и в итоге написал пару функций для отображения коллажа.
Так же внизу формировалась таблица с координатами планет.
Код отображения планет в головном файле:
//======================================Планеты======================================================================
for (var i = 0; i < (planets.length); i++){
var tyu=planetposition(planets[i][0], planets[i][1], jdn, planets[i][3], planets[i][4], planets[i][5], planets[i][6], planets[i][7], planets[i][8],planets[i][9],planets[i][10])
if (i==0){
sundelta=tyu[1]
}
if (planetinfo1==1){
//Формирование таблицы "инфо о планетах"
res+="<tr><td>"+planets[i][8]+"</td><td>"+deltafloor(tyu[1])+"</td><td>"+alphafloor(tyu[0])+"</td><td>"+(tyu[3]).toFixed(3)+"</td><td>"+(tyu[2]).toFixed(1)+"</td><td>"+(2*tyu[4]).toFixed(1)+"</td></tr>";
}
var zl=atmospheric_refraction(equatorial_to_horizontal(tyu[1], sr-15*tyu[0], phi)[1]);//Зенитное расстояние
if (i==0){
sunz=zl
}
//alert(tyu)
if (i>0){
draw(ctx, tyu[4], i,tyu[3],planets[i][8], date);
}
if (zl<90){
var Az=equatorial_to_horizontal(tyu[1], sr-15*tyu[0], phi)[0]; //Азимут
var cor1=to_xy(zl,Az);
var x=(cor1[0]*1).toFixed(0);//Абцисс координата
var y=(cor1[1]*1).toFixed(0);//Ординат
var R=Math.round((9-1*tyu[2])*kp2);
if (R>10){
R=10
var R1=20*R
if (planets[i][8]=='Солнце'){ //Делаем большой ореол для Солнца
R=7
sunx=x
suny=y
}
}else{
var R1=kp1*R
}
var circl = new LC.Circle( x,y,R); //Рисуем круг планеты
var circl2 = new LC.Circle( x,y,R1); //Рисуем круг ореола
ct.fill(circl, 'rgba('+planets[i][11][0]+','+planets[i][11][1]+','+planets[i][11][2]+',1)'); //заливаем круг планеты
//пишем название планеты
ct.text({
text: planets[i][8],
padding: [ 1*y, 1*x],
size:15,
color:'rgba('+planets[i][11][0]+','+planets[i][11][1]+','+planets[i][11][2]+',1)'
});
//alert(planets[i][11][0])
//Заливаем ореол градиентом-----
ct.fill(circl2, ct
.createRadialGradient(
new LC.Circle(x, y, 1),
new LC.Circle(x, y, R1))
.addColorStop({
'0.0': 'rgba('+planets[i][11][0]+','+planets[i][11][1]+','+planets[i][11][2]+',0.85)',
'1.0': 'rgba('+planets[i][11][0]+','+planets[i][11][1]+','+planets[i][11][2]+',0)'
}));/**/
//----------
}
}
Луна
Я решил не мучатся, и не стал вырисовывать Луну вместе с фазой, потому что нагрузка и так высока.
Для отображения положения Луны брал готовый алгоритм Яна Мееуса, который нашёл на окраинах Интернета, поэтому решил его немного изменить и перепостить на :github
Кометы и астероиды
Здесь я до сих пор стою на перепутье, потому что сложно сказать насколько нужна эта функция: как правило кометы и астероиды слишком слабы для наблюдений. Поэтому я сделал только раздел для самых ярких комет. Собственно была написана библиотека вычисления положения кометы на параболической орбите: github
Проблемы и пути их решения
Главной проблемой является медлительность программы, особенно при быстром прокручивании. Тут сложно что-то сделать, наверное стоит алгоритмы урезать, но это моё мнение… На самом деле, я нечасто использую увеличение, поэтому этот баг редко ощущаю.
Находиться программа здесь:http://astrokot.ru/planetarium/dev/planetarium.html
Автор: Lord_Katler_Bekket