 
// A HTML widget for showing 3 North pointers, Grid, True and Magnetic


 
function BdccNorthWidget(div, gridColour, magColour, trueColour, backColour) {

	this.gridColour = gridColour || "#000000";
	this.magColour = magColour || "#FF0000";
	this.trueColour = trueColour || "#0000FF";
	this.backColour = backColour || null;
	this.container = div;
}

BdccNorthWidget.prototype.destroy = function() {
  if((this.div != null)&&(this.container != null))
	   this.container.removeChild(this.div);
  
}

BdccNorthWidget.prototype.draw = function(convergence, declination) {

	//origin for all 3 north lines is centre bottom + 10% of height
	
	this.destroy(); 
	this.div = document.createElement("DIV");
    this.container.appendChild(this.div);
	this.div.style.position='absolute';
	this.div.style.width = this.container.offsetWidth + 'px';
	this.div.style.height = this.container.offsetHeight + 'px';
	this.div.style.top = 0 + 'px';
	this.div.style.left = 0 + 'px';
	this.div.style.border = '0px';
	if(!this.backColour)
	    this.div.style.background = 'none';	
	else
	    this.div.style.background = this.backColour;	
		

    
    //draw reference line - grid north
    var title = "Grid North";
	var p1x = this.div.offsetWidth / 2;
	var p1y = this.div.offsetHeight * 0.9;
	var p2y = this.div.offsetHeight * 0.1;
	var l = p1y - p2y;
	var p2x = p1x;
    
    this.buildLine(this.div,p2x,p2y-1,p1x,p1y,this.gridColour,2,0.99,title);
    this.buildLine(this.div,p2x,p2y,p2x-5,p2y+8,this.gridColour,2,0.99,title);
    this.buildLine(this.div,p2x+1,p2y,p2x+6,p2y+8,this.gridColour,2,0.99,title);

    //When convergence is +ve, True north is West of Grid north.
    var label;
    var d;
    var m;
    if(convergence >= 0){
        title = "True North is " + convergence.toFixed(2) + " degrees West of Grid North";
        d = Math.floor(convergence);
        m = Math.round((convergence - d)*60.0); 
        if (m < 10)
            m = '0' + m.toString();
        label = d+ "W" + m + "'";
    }
    else{
        title = "True North is " + (-convergence.toFixed(2)) + " degrees East of Grid North";
        d = Math.floor(-convergence);
        m = Math.round(((-convergence) - d)*60.0); 
        if (m < 10)
            m = '0' + m.toString();
        label = d+ "E" + m + "'";
    }
    var theta = convergence*Math.PI/45.0; // scale x 4
    p2x = Math.round(p1x - (l * 0.9 * Math.sin(theta)));
    p2y = Math.round(p1y - (l * 0.9 * Math.cos(theta)));
    this.buildLine(this.div,p2x,p2y,p1x,p1y,this.trueColour,1,0.99,title);
                
    theta -= Math.PI/6;
    var hdx1 = Math.round(8*Math.sin(theta));
    var hdy1 = Math.round(8*Math.cos(theta));
    theta += Math.PI*2/6;
    var hdx2 = Math.round(8*Math.sin(theta));
    var hdy2 = Math.round(8*Math.cos(theta));
    this.buildLine(this.div,p2x,p2y,p2x+hdx1,p2y+hdy1,this.trueColour,1,0.99,title);
    this.buildLine(this.div,p2x,p2y,p2x+hdx2,p2y+hdy2,this.trueColour,1,0.99,title);
                
                
	var dv = document.createElement("DIV");
	this.div.appendChild(dv);
	dv.style.position = "absolute";
	dv.style.border = "none";
	dv.style.padding = '1px';
	dv.style.color = this.trueColour;
	dv.style.background = "#8F8F8F";
	dv.style.fontFamily='Arial, Helvetica, sans-serif';
	dv.style.fontSize='8pt';
	dv.innerHTML = label;
	dv.style.left = "0px";
	dv.title = title;
	dv.style.top = this.div.offsetHeight - dv.offsetHeight + 'px';    
        
    //When declination is +ve, Magnetic North is East of True North
    var mag2Grid = convergence - declination;
    if(mag2Grid >= 0){
        title = "Magnetic North is " + mag2Grid.toFixed(2) + " degrees West of Grid North";
        label = mag2Grid.toFixed(2) + "W";
        d = Math.floor(mag2Grid);
        m = Math.round((mag2Grid - d)*60.0); 
        if (m < 10)
            m = '0' + m.toString();
        label = d+ "W" + m + "'";
    }
    else{
        title = "Magnetic North is " + (-mag2Grid.toFixed(2)) + " degrees East of Grid North";
        d = Math.floor(-mag2Grid);
        m = Math.round(((-mag2Grid) - d)*60.0); 
        if (m < 10)
            m = '0' + m.toString();
        label = d+ "E" + m + "'";
    }
    theta = mag2Grid*Math.PI/45.0;//scale x 4
    p2x = Math.round(p1x - (l * 0.8 * Math.sin(theta)));
    p2y = Math.round(p1y - (l * 0.8 * Math.cos(theta)));    
    this.buildLine(this.div,p2x,p2y,p1x,p1y,this.magColour,1,0.99,title);    

    theta -= Math.PI/6;
    var hdx1 = Math.round(8*Math.sin(theta));
    var hdy1 = Math.round(8*Math.cos(theta));
    theta += Math.PI*2/6;
    var hdx2 = Math.round(8*Math.sin(theta));
    var hdy2 = Math.round(8*Math.cos(theta));
    this.buildLine(this.div,p2x,p2y,p2x+hdx1,p2y+hdy1,this.magColour,1,0.99,title);
    this.buildLine(this.div,p2x,p2y,p2x+hdx2,p2y+hdy2,this.magColour,1,0.99,title);


	var dv = document.createElement("DIV");
	this.div.appendChild(dv);
	dv.style.position = "absolute";
	dv.style.border = "none";
	dv.style.padding = '1px';
	dv.style.color = this.magColour;
	dv.style.fontFamily='Arial, Helvetica, sans-serif';
	dv.style.fontSize='8pt';
	dv.style.background = "#8F8F8F";
	dv.innerHTML = label;
	dv.style.top = this.div.offsetHeight - dv.offsetHeight + 'px'; 
	dv.style.left = this.div.offsetWidth - dv.offsetWidth + 'px'; 
	dv.title = title;

}




//Create a div holding a set of horz and vert line segments making up the line between p1 and p2
//Uses this.sx,sy,ex,ey,steep

BdccNorthWidget.prototype.buildLine = function(cntnr,x0,y0,x1,y1,colour,width,opacity,title) {

 
  //Bresenham algorithm for line drawing see - wikipedia

  this.steep = false;
  if(Math.abs(y1 - y0) > Math.abs(x1 - x0))
	this.steep = true;
    
  if (this.steep){
		 var t = x0;
		 x0 = y0;
		 y0 = t;
		 
		 t = x1;
		 x1 = y1;
		 y1 = t;
  }
  if (x0 > x1){
		 var t = x0;
		 x0 = x1;
		 x1 = t;

		 t = y0;
		 y0 = y1;
		 y1 = t;
  }

  var deltax = x1 - x0;
  var deltay = Math.abs(y1 - y0);
  var error = 0;
  var ystep;
  var y = y0;
  
  if (y0 < y1)
	ystep = 1; 
  else 
	ystep = -1;
	

  //start and end coords of each horz/vertical line segment
  //We want to use the min of divs


  //initial coord of first line segment  
  if (this.steep){ 
     this.sx = y0;
     this.sy = x0;
  } 
  else{ 
     this.sy = y0;
     this.sx = x0;
  }


  var div = null;//a div whose background is a horz or vert line segment
  var last = false;//force last plot 
      
  //main Bresenham loops
  if (this.steep){ 
      for( var x = x0; x <= x1; x++){
    		 
	     if (x == x1)
		    last = true;
			
         div = this.plotLinePoint(y,x,last,colour,width,opacity,title); 

	     if(div != null)
		    cntnr.appendChild(div);
         //else point being held over until horz/vert segment ends 
    
         error = error + deltay;
         if ((2*error) >= deltax){
             y = y + ystep;
             error = error - deltax;
         }
      }  
  }
  else{
      for( var x = x0; x <= x1; x++){
    		 
	     if (x == x1)
		    last = true;
			
         div = this.plotLinePoint(x,y,last,colour,width,opacity,title);

	     if(div != null)
		    cntnr.appendChild(div);
         //else point being held over until horz/vert segment ends 
    
         error = error + deltay;
         if ((2*error) >= deltax){
             y = y + ystep;
             error = error - deltax;
         }        
      }    
   }
}


//Plot a point that is part of a horizontal or vertical line
//only emit a div if a horz or vert segment has been completed.
//Uses this.sx,sy,ex,ey,steep

BdccNorthWidget.prototype.plotLinePoint = function(x,y,last,colour,width,opacity,title) {
	     
		 this.ey = y;//end coords of line segment
		 this.ex = x;
		 var w2 = width / 2;

		 if((x == this.sx)&&(!last))
			return null;//same x coord as last point
		 if((y == this.sy)&&(!last))
			return null;//same y coord as last point

		 		 
		 //swap start and end to get +ve width and height
		 var ox = this.ex;
		 if(this.ex < this.sx){
			var t = this.ex;
			this.ex = this.sx;
			this.sx = t;
		 } 		 

		 var oy = this.ey;
		 if(this.ey < this.sy){
			var t = this.ey;
			this.ey = this.sy;
			this.sy = t;
		 } 	
		 
		 //establish width/height of div
		 var w = this.ex - this.sx;
		 var h = this.ey - this.sy;
		 
		 var x = this.sx;
		 var y = this.sy;
         if(this.steep){
            w = width;
            x -= w2;//centre the line segment according to the line width
            }
         else{
            h = width;
            y -= w2;//centre the line segment according to the line width
            }

	     this.sx = ox;//restore original bresenham coords of segment start
	     this.sy = oy;
		 
         //actually make the div		 		 
		 var div = document.createElement("DIV");
		 div.title = title;
	     var ds = div.style;
	     
	     ds.position = "absolute";
	     ds.overflow = "hidden";
	     ds.backgroundColor = colour;
	     ds.left = x + "px";
	     ds.top = y + "px";
	     ds.width = w + "px";
	     ds.height = h + "px";
	     	     
	     if(opacity != 1.0){
	        ds.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=" + Math.round(opacity * 100) +")";
	        ds.opacity = opacity;
	     }
	     	     
	     return div;
}


