Una bussola con javascript

Creato il 28 aprile 2012 da Marez @AndreaMarketto
Partendo dalla libreria Highstock o Highcharts (http://www.highcharts.com/) è possibile realizzare una semplice ma funzionale bussola in Javascript che indichi i punti cardinali e una direzione.
Come detto sopra occorre la libreria Highstock, la cui licenza è a pagamento ma è possibile scaricarla gratuitamente dal sito per provarla. Ritengo questa forma di vendita davvero intelligente in quanto permette agli sviluppatori di provare il prodotto prima di comprarlo.
Per far funzionare la nostra bussola sarà necessario includere la libreria nel nostro sito. Ci basterà aggiungerla nell'header con questo codice

<script src="http://www.agriculturalsupport.it/wp-content/themes/provisionpress/js/highstock.js" type="text/javascript">
</script>

Passiamo quindi alla creazione di un DIV con un ID specifico all'interno della pagina.

<div id="chart"></div>

A questo punto non dobbiamo fare altro che creare un grafico di tipo "gauge". Ovvero i grafici che indicano un valore con la lancetta. In rete si trovano esempi di come creare gauge a 180° ovvero π, ma noi dovremmo crearlo a 360° o meglio a .

function drawDial(options) {
var mis= 90;
var renderTo = options.renderTo,
  value = options.value,
  centerX = options.centerX,
  centerY = options.centerY,
  min = options.min,
  max = options.max,
  minAngle = options.minAngle,
  maxAngle = options.maxAngle,
  tickInterval = options.tickInterval,
  ranges = options.ranges;
  
var renderer = new Highcharts.Renderer(
  document.getElementById(renderTo),
  240,
  240
);
// internals
var angle,
  pivot;
function valueToAngle(value) {
  return (maxAngle - minAngle) / (max - min) * value-Math.PI/2 + minAngle;
}
function setValue(value) {
  // the pivot
  angle = valueToAngle(value);
  
  var path = [
   'M',
   centerX, centerY,
   'L',
   centerX + mis * Math.cos(angle), centerY + mis * Math.sin(angle)
   ];
  
  if (!pivot) {
  pivot = renderer.path(path)
  .attr({
  stroke: 'black',
  'stroke-width': 3
  })
  .add();
  } else {
  pivot.attr({
  d: path
  });
  }
}
// background area
renderer.arc(centerX, centerY, mis+5, 0, minAngle, maxAngle)
  .attr({
  fill: {
  linearGradient: [0, 0, 0, 200],
  stops: [
  [0, '#FFF'],
  [1, '#DDD']
  ]
  },
  stroke: 'silver',
  'stroke-width': 1
  })
  .add();
// ranges
$.each(ranges, function(i, rangesOptions) {
  renderer.arc(
  centerX,
  centerY,
  mis,
  mis-5,
  valueToAngle(rangesOptions.from),
  valueToAngle(rangesOptions.to)
  )
  .attr({
  fill: rangesOptions.color
  })
  .add();
});
// ticks
var dir;
for (var i = min; i <= max; i += tickInterval) {
dir=''
  if (i==0){dir='N'}
  if (i==90){dir='E'}
  if (i==180){dir='S'}
  if (i==270){dir='W'}
  if (i==360){dir='N'}
  angle = valueToAngle(i);
  
  // draw the tick marker
  renderer.path([
  'M',
  centerX + 90 * Math.cos(angle), centerY + 90 * Math.sin(angle),
  'L',
  centerX + 70 * Math.cos(angle), centerY + 70 * Math.sin(angle)
  ])
  .attr({
  stroke: 'silver',
  'stroke-width': 2
  })
  .add();
  
  // draw the text
  renderer.text(
  dir,
  centerX + 90 * Math.cos(angle),
  centerY + 90 * Math.sin(angle)
  )
  .attr({
  align: 'center'
  })
  .add();
  
}
// the initial value
setValue(value);
// center disc
renderer.circle(centerX, centerY, 20)
  .attr({
  fill: '#4572A7',
  stroke: 'black',
  'stroke-width': 1
  })
  .add();
return {
  setValue: setValue
};
}
  
  
// Build the dial
var dial = drawDial({
  renderTo: 'statsframe',
  value: 250, //<-- questo valore espresso in gradi indica la direzione
  centerX: 120,
  centerY: 120,
  min: 0,
  max: 360,
  minAngle: 0,
  maxAngle: 2*Math.PI,
  tickInterval: 45,
  ranges: [{
  from: 0,
  to: 45,
  color: '#D3fd53'
  }, {
  from: 45,
  to: 90,
  color: 'transparent'
  }, {
  from: 90,
  to: 135,
  color: '#D3fd53'
  }, {
  from: 135,
  to: 180,
  color: 'transparent'
  }, {
  from: 180,
  to: 225,
  color: '#D3fd53'
  }, {
  from: 225,
  to: 270,
  color: 'transparent'
  }, {
  from: 270,
  to: 315,
  color: '#D3fd53'
  }, {
  from: 315,
  to: 360,
  color: 'transparent'
  }]
});

Nel codice soprastante la variabile "mis" è utilizzata per stabilire la grandezza della nostra bussola. Assegnandole valori più grandi si ingrandirà anche la bussola. Dobbiamo però prestare attenzione anche ai parametri della variabile "render" che vanno a stabilire larghezza e lunghezza del div su cui la bussola viene rappresentata.
Per direzionare l'ago della bussola non dobbiamo fare altro che cambiare il valore del parametro "value" nella variabile dial, che è quella che costruisce il grafico. Il valore è espresso in gradi, perciò se vogliamo indicare il Nord il valore da assegnare sarà 0 (o 360), per l'Est sarà 90, per il Sud 180, per l'Ovest 270. Ovviamente possiamo assegnare un qualsiasi valore intermedio.