var CIRCLE_RADIUS = 0.75, REAR_ARROW_WIDTH = 0.18, FRONT_ARROW_WIDTH = 0.15, BEARING_ARROW_WIDTH = 0.08, BEARING_ARROW_LENGTH = 0.65, LETTER_SIZE = 0.1, LETTER_RADIUS = 0.88, global_angle = 200, COOKIE = "ressie_angle", spin_initialized = 0, dragging = 0, start_drag_angle = 0, old_global_angle = 0, WIND_STEPS = 20, WIND_TIME = 1, wind_start = 0, wind_end = 0, wind_step = 0, wind_timer = null, last_angle = null, cache_ctx = null, cache_canvas = null, minWidthHeight = 1, current_angle = null; function getContext() { if (cache_ctx) { return cache_ctx; } if (!cache_canvas) { cache_canvas = document.getElementById("compass"); if (typeof G_vmlCanvasManager != "undefined") { cache_canvas = G_vmlCanvasManager.initElement(cache_canvas); } minWidthHeight = Math.min(cache_canvas.width, cache_canvas.height); } if (cache_canvas) { cache_ctx = cache_canvas.getContext("2d"); } return cache_ctx; } function svgPathMap(svg_path, move_fun, line_fun, curve_fun, close_fun) { var i = 0; while (i < svg_path.length) { if (svg_path[i] == "M") { var move_xy = svg_path[i+1].split(","); move_fun(move_xy[0], move_xy[1]); i = i + 2; } else if (svg_path[i] == "L") { var line_xy = svg_path[i+1].split(","); line_fun(line_xy[0], line_xy[1]); i = i + 2; } else if (svg_path[i] == "C") { var xy1 = svg_path[i+1].split(","), xy2 = svg_path[i+2].split(","), xy3 = svg_path[i+3].split(","); curve_fun(xy1[0], xy1[1], xy2[0], xy2[1], xy3[0], xy3[1]); i = i + 4; } else if (svg_path[i] == "z") { close_fun(); i++; } else { alert("Unknown path element: " + svg_path[i]); } } } function drawPath(svg_path, ctx, fill, scale) { if (fill) { ctx.beginPath(); svgPathMap(svg_path, function(x, y) {ctx.moveTo(x*scale, y*scale);}, function(x, y) {ctx.lineTo(x*scale, y*scale);}, function(x1, y1, x2, y2, x, y) {ctx.bezierCurveTo(x1*scale, y1*scale, x2*scale, y2*scale, x*scale, y*scale);}, function() {ctx.fill();}); } else { ctx.beginPath(); svgPathMap(svg_path, function(x, y) {ctx.moveTo(x*scale, y*scale);}, function(x, y) {ctx.lineTo(x*scale, y*scale);}, function(x1, y1, x2, y2, x, y) {ctx.bezierCurveTo(x1*scale, y1*scale, x2*scale, y2*scale, x*scale, y*scale);}, function() {ctx.stroke();}); } } function drawCompass(ctx, scale) { // draw a compass, centred at (0, 0), bounded by (-scale, -scale), (scale, scale) ctx.save(); // draw background semi transparent filled circle //ctx.lineWidth = 0.75; ctx.strokeStyle = "rgb(136,136,136)"; ctx.fillStyle="rgba(255,255,255,0.5)"; ctx.beginPath(); ctx.arc(0, 0, CIRCLE_RADIUS * scale, 0, Math.PI * 2, true); ctx.closePath(); ctx.fill(); ctx.beginPath(); ctx.arc(0, 0, CIRCLE_RADIUS * scale, 0, Math.PI * 2, true); ctx.closePath(); ctx.stroke(); // draw background N, S, E, W arrows in blue var QUART = Math.sqrt(2)/2 * CIRCLE_RADIUS, SVG_BACK_ARROWS = ("M 0,-" + REAR_ARROW_WIDTH + " L " + QUART + ",-" + QUART + " L " + REAR_ARROW_WIDTH + ",0 L " + QUART + "," + QUART + " L 0," + REAR_ARROW_WIDTH + " L -" + QUART + "," + QUART + " L -" + REAR_ARROW_WIDTH + ",0 L -" + QUART + ",-" + QUART + " L 0,-" + REAR_ARROW_WIDTH + " z").split(" "); ctx.fillStyle = "rgb(0, 0, 255)"; drawPath(SVG_BACK_ARROWS, ctx, 1, scale); drawPath(SVG_BACK_ARROWS, ctx, 0, scale); var FRONT_45 = QUART * FRONT_ARROW_WIDTH * scale; for (var i = 0; i < 2; i++) { ctx.save(); for(var j=0; j<4; j++) { ctx.beginPath(); ctx.moveTo(0, 0); ctx.lineTo(FRONT_45, -FRONT_45); ctx.lineTo(0, -scale); ctx.lineTo(0, 0); ctx.closePath(); if (i === 0) { ctx.fillStyle = "rgb(255,0,0)"; ctx.fill(); } else { ctx.stroke(); } ctx.beginPath(); ctx.moveTo(0, 0); ctx.lineTo(-FRONT_45, -FRONT_45); ctx.lineTo(0, -scale); ctx.lineTo(0, 0); ctx.closePath(); if (i === 0) { ctx.fillStyle = "rgb(255,255,255)"; ctx.fill(); } else { ctx.stroke(); } ctx.rotate(Math.PI / 2); } ctx.restore(); } var NORTH_PATH = ("M -" + (LETTER_SIZE / 1.4) + ",-" + (LETTER_RADIUS - LETTER_SIZE) + " L -" + (LETTER_SIZE / 1.4) + ",-" + (LETTER_RADIUS + LETTER_SIZE) + " L " + (LETTER_SIZE / 1.4) + ",-" + (LETTER_RADIUS - LETTER_SIZE) + " L " + (LETTER_SIZE / 1.4) + ",-" + (LETTER_RADIUS + LETTER_SIZE) + " z").split(" "); ctx.lineWidth = 3.0; ctx.lineJoin = 'round'; ctx.strokeStyle = "rgba(255,255,255,0.9)"; drawPath(NORTH_PATH, ctx, 0, scale); ctx.lineWidth = 1.0; ctx.strokeStyle = "rgb(0,0,0)"; drawPath(NORTH_PATH, ctx, 0, scale); ctx.restore(); } function drawArrow(ctx, scale) { ctx.save(); var ARROW_PATH = ("M -0.05,-0.15 L 0.05,-0.15 L 0.05,0.25 L 0.1,0.25 " + "L 0,0.4 L -0.1,0.25 L -0.05,0.25 L -0.05,-0.15 z").split(" "); ctx.lineWidth = 1.0; ctx.strokeStyle = "rgb(0,0,0)"; ctx.fillStyle = "rgb(238, 238, 0)"; ctx.lineJoin = "round"; drawPath(ARROW_PATH, ctx, 1, scale); drawPath(ARROW_PATH, ctx, 0, scale); ctx.restore(); } function drawRessie(ctx, scale) { var SVG_PATH=("M 242.14286,620.93361 C 242.14286,620.93361 307.14286,540.93361 318.57143,526.6479 "+ "C 330,512.36218 309.28571,498.07647 309.28571,498.07647 C 309.28571,498.07647 291.19688,481.65613 287.85714,477.36218 "+ "C 282.85715,470.93361 290.78801,462.50108 298.57143,463.79075 C 310.72728,465.80491 334.28571,463.79075 347.85714,456.6479 "+ "C 361.42857,449.50504 360.71429,440.21933 370,435.21933 C 379.28571,430.21933 390,425.93361 407.14286,423.07647 "+ "C 424.05247,420.2582 430.71429,413.07647 437.14286,409.50504 C 443.57143,405.93361 450,398.07647 451.42857,405.21933 "+ "C 452.85714,412.36218 480,520.93361 480,520.93361 C 480,520.93361 447.14286,551.6479 440,555.93361 "+ "C 432.85714,560.21933 427.85714,567.36218 423.57143,567.36218 C 419.28571,567.36218 409.28571,574.50504 409.28571,574.50504 "+ "L 408.57143,594.50504 C 408.57143,594.50504 407.85714,615.21933 405,615.93361 "+ "C 402.14286,616.6479 392.14286,625.93361 375,613.79075 C 357.85714,601.6479 337.14286,593.07647 327.14286,595.93361 "+ "C 317.14286,598.79075 298.57143,603.07647 298.57143,603.07647 C 298.57143,603.07647 265,641.6479 259.28571,641.6479 "+ "C 253.57143,641.6479 243.57143,643.07647 240.71429,635.93361 C 237.85714,628.79076 242.14286,621.6479 242.14286,620.93361 z").split(" "); var max_x = 0, max_y = 0, min_x = 2000, min_y = 2000; function bound(x, y) { max_x = Math.max(max_x, x); max_y = Math.max(max_y, y); min_x = Math.min(min_x, x); min_y = Math.min(min_y, y); } svgPathMap(SVG_PATH, bound, bound, function(cx1, cy1, cx2, cy2, x, y) {bound(x, y);}, function() {}); ctx.save(); //ctx.translate(minWidthHeight / 2, minWidthHeight / 2); // cCtx.rotate(Math.PI / 180 * ressie_angle); var thisScale = scale / Math.max(max_x - min_x, max_y - min_y) * 2 / Math.sqrt(2); ctx.scale(thisScale, thisScale); ctx.translate(-(min_x + max_x) / 2, -(min_y + max_y) / 2); ctx.beginPath(); ctx.strokeStyle = "rgb(136, 136, 136)"; ctx.fillStyle = "rgb(34, 170, 238)"; svgPathMap(SVG_PATH, function(x, y) {ctx.moveTo(x, y);}, function(x, y) {ctx.lineTo(x, y);}, function(x1, y1, x2, y2, x, y) {ctx.bezierCurveTo(x1, y1, x2, y2, x, y);}, function() {ctx.closePath(); ctx.fill();}); svgPathMap(SVG_PATH, function(x, y) {ctx.moveTo(x, y);}, function(x, y) {ctx.lineTo(x, y);}, function(x1, y1, x2, y2, x, y) {ctx.bezierCurveTo(x1, y1, x2, y2, x, y);}, function() {ctx.closePath(); ctx.stroke();}); ctx.restore(); } function drawAll(ctx, wind_angle) { ctx.clearRect(0, 0, cache_canvas.width, cache_canvas.height); ctx.save(); ctx.translate(minWidthHeight / 2, minWidthHeight / 2); ctx.rotate(Math.PI * global_angle / 180); drawRessie(ctx, minWidthHeight / 2); ctx.restore(); ctx.save(); ctx.translate(minWidthHeight / 4, minWidthHeight / 4); ctx.rotate(Math.PI * global_angle / 180); drawCompass(ctx, minWidthHeight / 4); ctx.restore(); ctx.save(); ctx.translate(minWidthHeight / 2, minWidthHeight / 2); ctx.rotate(Math.PI * (global_angle) / 180 + wind_angle); drawArrow(ctx, minWidthHeight / 2); ctx.restore(); } function initSpin(canvas) { var start, end, value; if (document.cookie.length > 0) { start = document.cookie.indexOf(COOKIE + "="); if ((start != -1) && (document.cookie.length >= start + COOKIE.length + 1)) { end = document.cookie.indexOf(";", start + COOKIE.length + 1); if (end == -1) { end = document.cookie.length; } global_angle = parseInt(unescape(document.cookie.substring(start + COOKIE.length + 1, end)), 10); } } $('#compass').mousedown(function(event){ if (dragging === 0) { var x = event.clientX - (canvas.width / 2), y = event.clientY - (canvas.height / 2), elem = canvas; while (elem) { x -= elem.offsetLeft; y -= elem.offsetTop; elem = elem.offsetParent; } start_drag_angle = Math.atan2(y, x); old_global_angle = global_angle; dragging = 1; } }).mousemove(function(event){ if (dragging == 1) { var x = event.clientX - (canvas.width / 2), y = event.clientY - (canvas.height / 2), elem = canvas; while (elem) { x -= elem.offsetLeft; y -= elem.offsetTop; elem = elem.offsetParent; } var current = Math.atan2(y, x); global_angle = old_global_angle + (current - start_drag_angle) * 180 / Math.PI; drawAll(cache_ctx, current_angle); } }).mouseup(function(event){ if (dragging == 1) { dragging = 0; if (global_angle != old_global_angle) { drawAll(cache_ctx, current_angle); var date = new Date(); date.setTime(date.getTime() + (10*365.25*60*60*1000)); var expires = "; expires="+date.toGMTString(); document.cookie = COOKIE + "=" + Math.floor(global_angle) + expires + "path=/"; } } }).mouseout(function(event){ if (dragging == 1) { dragging = 0; global_angle = old_global_angle; drawAll(cache_ctx, current_angle); } }); spin_initialized = 1; } function drawStep() { var ctx = getContext(); if (ctx) { if (spin_initialized === 0) { initSpin(cache_canvas); } var ratio = (1-Math.cos(wind_step / WIND_STEPS * Math.PI))/2; current_angle = wind_start + (wind_end - wind_start) * ratio; drawAll(ctx, current_angle); } if (wind_step < WIND_STEPS) { wind_step = wind_step + 1; } else { clearInterval(wind_timer); wind_timer = null; wind_start = wind_end; } } function drawWind(angle) { if (last_angle && (last_angle === angle)) { return; } last_angle = angle; wind_end = angle / 180 * Math.PI; if ((wind_end - wind_start) > Math.PI) { wind_end = wind_end - 2 * Math.PI; } wind_step = 0; if (wind_timer !== null) { clearInterval(wind_timer); wind_start = current_angle; } wind_timer = setInterval(drawStep, WIND_TIME * 1000 / WIND_STEPS); }