HEX
Server: nginx/1.24.0
System: Linux nowruzgan 6.8.0-57-generic #59-Ubuntu SMP PREEMPT_DYNAMIC Sat Mar 15 17:40:59 UTC 2025 x86_64
User: babak (1000)
PHP: 8.3.6
Disabled: NONE
Upload Files
File: /var/www/nowruzgan.com/vis/astrolabe/lib/scripts.js
var mouseIn = false;
var mouseDown = false;
var dragging = false;
var actionLayer;
var reteLayer;
var boundingRect;
var alpha = 0;
var refAlpha = 0;
var rotationAlpha = 0;
var direction = {lastAlpha: 0, sign: 0, textSign: false};
var transformationAlpha = 0;
var ctx;
var drawStars = true;

var stars = [
  { x: 394, y: 315, en: 'Deneb Dulfim', fa: 'ذنب الدلفین' },
  { x: 286, y: 352, en: '02', fa: 'شماره ۰۲' },
  { x: 297, y: 484, en: 'Merga', fa: 'المرأةالمسلسله' },
  { x: 417, y: 488, en: 'Caph', fa: 'کف الخضیب' },
  { x: 443, y: 415, en: 'Deneb', fa: 'ردف' },
  { x: 392, y: 794, en: 'Rigel', fa: 'رجل الجبار' },
  { x: 427, y: 814, en: 'Rigel', fa: 'رجل الجبار' },
  { x: 518, y: 850, en: 'Sirius', fa: 'شعرای یمانی' },
  { x: 651, y: 624, en: 'Regulus', fa: 'قلب الاسد' },
  { x: 400, y: 572, en: 'Algol', fa: 'رأس الغول' },
  { x: 456, y: 601, en: 'Capella', fa: 'عیّوق' },
  { x: 244, y: 237, en: 'Deneb Algedi', fa: 'ذنب الجدی' },
  { x: 295, y: 654, en: 'Kaffaljidhm', fa: 'کف الجذماء' },
  { x: 203, y: 577, en: '14', fa: 'جبهة قیطس' },
  { x: 162, y: 443, en: 'Dheneb', fa: 'ذنب قیطس' },
  { x: 605, y: 398, en: 'Alfecca Meridiana', fa: 'فکه' },
  { x: 500, y: 386, en: 'Vega', fa: 'نسر واقع' },
  { x: 416, y: 369, en: '18', fa: 'جناح الدجاجة' },
  { x: 593, y: 371, en: '19', fa: 'منکب الجاثی' },
  { x: 577, y: 564, en: '20', fa: 'شماره ۲۰' },
  { x: 587, y: 484, en: 'Almach', fa: 'العناق' },
  { x: 656, y: 431, en: 'Arcturus', fa: 'سماک رامح' },
  { x: 492, y: 702, en: '23', fa: 'شماره ۲۳' },
  { x: 505, y: 708, en: 'Alhena', fa: 'هنعه' },
  { x: 455, y: 731, en: 'Betelgeuse', fa: 'الید الجوزا' },
  { x: 423, y: 727, en: 'Betelgeuse', fa: 'الید الجوزا' },
  { x: 398, y: 671, en: 'Ain', fa: 'عین الثور' },
  { x: 623, y: 849, en: '28', fa: 'شماره ۲۸' },
  { x: 563, y: 726, en: 'Procyon', fa: 'شعرای شامی' },
  { x: 437, y: 279, en: 'Altair', fa: 'نسر طایر' },
  { x: 557, y: 301, en: 'Ras Alhague', fa: 'رأس الحوّاء' },
  { x: 659, y: 347, en: 'Unuk / Unukalhai', fa: 'عُنُق الحیه' },
  { x: 732, y: 182, en: 'Antares', fa: 'قلب العقرب' },
  { x: 685, y: 713, en: 'Alphard', fa: 'الفرد' },
  // { x: 502, y:  97, en: '35', fa: 'شماره ۳۵' },
  { x: 793, y: 456, en: 'Spica', fa: 'سماک اعزل' },
  { x: 779, y: 322, en: '37', fa: 'شماره ۳۷' },
  { x: 796, y: 643, en: '38', fa: 'شماره ۳۸' },
  { x: 829, y: 549, en: 'Gienah Gurab', fa: 'جناح الغراب' },
  { x: 620, y: 648, en: 'Alterf', fa: 'طرف' },
];

window.addEventListener('load', () => init());

function init() {
  actionLayer = document.querySelector('.layer.action');
  reteLayer = document.querySelector('.layer.rete');
  boundingRect = actionLayer.getBoundingClientRect();
  ctx = document.querySelector('.layer.overlay canvas').getContext('2d');
  ctx.fillStyle = 'rgba(0, 0, 0, 0)';
  ctx.font = '10px Farhang';
  ctx.fillText('الف', 0, 0)

  window.addEventListener('touchstart', event => { console.log('touchstart'); press(event); });
  window.addEventListener('mousedown', event => press(event));
  window.addEventListener('touchmove', event =>  { console.log('touchmove'); move(event); });
  window.addEventListener('mousemove', event => move(event));
  window.addEventListener('touchend', event =>  { console.log('touchend'); release(); });
  window.addEventListener('touchcancel', event =>  { console.log('touchcancel'); release(); });
  window.addEventListener('mouseup', event => release(event));
  window.addEventListener('click', event => click(event));

  for(let star of stars) {
    star.transX = star.x;
    star.transY = star.y;
  }

  redraw();
}

function click(event) {
  if(event.type == 'touchmove'){
    event.x = event.touches[0].pageX;
    event.y = event.touches[0].pageY;
  }
  let x = (event.x - boundingRect.x) / boundingRect.width;
  let y = (event.y - boundingRect.y) / boundingRect.height;

  if(!dragging)
    for(let star of stars)
      star.selected = Math.sqrt((star.transX - x*1000)**2 + (star.transY - y*1000)**2) < 10;
  dragging = false;

  redraw();
}

function press(event) {
  dragging = false;
  if(!mouseIn) return;

  mouseDown = true;
  refAlpha = alpha;
  rotationDirection = 0;
  direction.lastAlpha = alpha;
  direction.d = 0;
}

function move(event) {
  if(event.type == 'touchmove'){
    event.x = event.touches[0].pageX;
    event.y = event.touches[0].pageY;
  }
  let x = (event.x - boundingRect.x) / boundingRect.width - .5;
  let y = (event.y - boundingRect.y) / boundingRect.height - .5;

  if(Math.sqrt(x**2 + y**2)<.416 || mouseDown) {
    mouseIn = true;
    actionLayer.classList.add('hover');
    alpha = Math.atan2(y, x);
    if(alpha<0) alpha += 2*Math.PI;

    for(let star of stars)
      star.hover = Math.sqrt((star.transX - (x+.5)*1000)**2 + (star.transY - (y+.5)*1000)**2) < 10;

    if(mouseDown) {
      dragging = true;
      transformationAlpha = rotationAlpha + (alpha - refAlpha);
      reteLayer.style.transform = `rotate(${transformationAlpha}rad)`;

      if(alpha!=direction.lastAlpha) {
        let delta1 = delta(refAlpha, direction.lastAlpha);
        let delta2 = delta(refAlpha, alpha);
        let delta3 = delta(direction.lastAlpha, alpha);
        if(delta3.d>=delta1.d && delta3.d>=delta2.d)
          direction.sign = delta2.s;
        direction.textSign = (direction.sign && alpha<refAlpha) || (!direction.sign && alpha>refAlpha);
        direction.lastAlpha = alpha;
      }
    }
    redraw();
  }else {
    actionLayer.classList.remove('hover');
    mouseIn = false;
    if(mouseDown)
      release();
  }
}

function release(event) {
  mouseDown = false;
  rotationAlpha += alpha - refAlpha;
  refAlpha = 0;
  redraw();
}

function redraw() {
  ctx.clearRect(0, 0, 1000, 1000);

  if(mouseDown) {
    ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
    ctx.beginPath();
    ctx.arc(500, 500, 415, refAlpha, alpha, !direction.sign);
    ctx.lineTo(Math.cos(alpha)*438 + 500, Math.sin(alpha)*438 + 500);
    ctx.arc(500, 500, 438, alpha, refAlpha, direction.sign);
    ctx.lineTo(Math.cos(refAlpha)*415 + 500, Math.sin(refAlpha)*415 + 500);
    ctx.fill();

    ctx.strokeStyle = 'white';
    ctx.lineWidth = 2;
    ctx.beginPath();
    ctx.moveTo(500, 500);
    ctx.lineTo(Math.cos(alpha)*500 + 500, Math.sin(alpha)*500 + 500);
    ctx.moveTo(500, 500);
    ctx.lineTo(Math.cos(refAlpha)*500 + 500, Math.sin(refAlpha)*500 + 500);
    ctx.stroke();

    let text = Math.abs(alpha - refAlpha);
    if(direction.textSign)
      text = 2*Math.PI - text;
    text = (text*180/Math.PI).toFixed()+'°';
    ctx.save();
    ctx.fillStyle = 'black';
    ctx.textAlign = 'center';
    let rotation = (alpha+refAlpha)/2; 
    if(direction.textSign)
      rotation += Math.PI;
    ctx.translate(Math.cos(rotation)*420 + 500, Math.sin(rotation)*420 + 500)
    ctx.rotate(rotation + Math.PI/2);
    ctx.font = '18px monospace';
    ctx.fillText(text, 0, 0);
    ctx.restore();
  }

  if(drawStars) {
    for(let star of stars) {
      let x = star.x - 500;
      let y = star.y - 500;
      let _alpha = Math.atan2(y, x);
      let r = Math.sqrt(x*x + y*y);
      let theta = _alpha + transformationAlpha;

      if(mouseDown) {
        ctx.beginPath();
        ctx.strokeStyle = 'rgba(255, 255, 255, .75)';
        ctx.lineWidth = 2;
        ctx.arc(500, 500, r, rotationAlpha+_alpha, rotationAlpha + _alpha + alpha-refAlpha, !direction.sign);
        ctx.stroke();
      }

      ctx.beginPath();
      ctx.fillStyle = '#37C7FF';
      ctx.strokeStyle = '#404040';
      ctx.lineWidth = 1;
      star.transX = r*Math.cos(theta) + 500;
      star.transY = r*Math.sin(theta) + 500;
      ctx.arc(star.transX, star.transY, ((star.hover && !dragging) || star.selected) ? 10 : 5, 0, 2*Math.PI);
      ctx.stroke();
      ctx.fill();
      // ctx.fillStyle = '#FFFFFF';
      // ctx.textAlign = 'center';
      // ctx.fillText(star.en, star.transX, star.transY+2)
    }

    for(let star of stars)
      if(star.selected) {
        ctx.lineWidth = 1;
        ctx.strokeStyle = 'rgba(255, 255, 255, .5)';
        ctx.fillStyle = 'rgba(70, 70, 70, .85)';
        ctx.beginPath();
        ctx.moveTo(star.transX, star.transY+5);
        ctx.lineTo(star.transX+5, star.transY+10);
        ctx.lineTo(star.transX+70, star.transY+10);
        ctx.lineTo(star.transX+70, star.transY+60);
        ctx.lineTo(star.transX-70, star.transY+60);
        ctx.lineTo(star.transX-70, star.transY+10);
        ctx.lineTo(star.transX-5, star.transY+10);
        ctx.lineTo(star.transX, star.transY+5);
        ctx.fill();
        ctx.stroke();
        ctx.font = '14px Farhang';
        ctx.fillStyle = 'white';
        ctx.textAlign = 'center';
        ctx.fillText(star.en, star.transX, star.transY+30);
        ctx.font = '16px Farhang';
        ctx.fillText(star.fa, star.transX, star.transY+50);
      }
  }
}

function delta(a1, a2) {
  let d = Math.abs(a1 - a2);
  let _d = d;
  if(d > Math.PI)
    d = 2*Math.PI - d;
  let s = (a2>a1 && d==_d) || (a2<a1 && d!=_d);
  return {d, s};
}