Skip to content

Instantly share code, notes, and snippets.

@bsparks
Created September 1, 2015 21:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bsparks/e8e19910c15e6caa2dea to your computer and use it in GitHub Desktop.
Save bsparks/e8e19910c15e6caa2dea to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<title>Graph Paper</title>
<script type="text/javascript">
/* Declare global variables */
var spacing = 18;
var canvas;
var ctx;
var line;
var actions;
var popup;
var toolset_coord;
/* Called when everything is ready */
function BodyLoad() {
/* Assign elements to variables */
popup = document.getElementById('popup');
canvas = document.getElementById('canvas');
toolset_coord = document.getElementById('coord');
/* Set up the canvas context (ctx) */
ctx = canvas.getContext('2d');
/* Set some canvas properties */
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.w = canvas.width; // short-hand
canvas.h = canvas.height; // short-hand
canvas.mousedown = false;
/* Update the coordinates in the toolset */
toolset_coord.update = function(x,y) {
this.innerHTML = x+','+y;
}
/* For keeping up with what we've done */
actions = {
data: [], // empty on start
/* Store to the array */
save: function() {
this.data[this.data.length] = {
x1: line.x1,
y1: line.y1,
x2: line.x2,
y2: line.y2,
type: 'line',
color: line.color,
width: line.width
}
},
/* Loop through the array and re-draw lines */
restore: function() {
for(var i=0;i<this.data.length;i++)
line.draw(this.data[i].x1, this.data[i].y1, this.data[i].x2, this.data[i].y2, 'restore', this.data[i].color, this.data[i].width);
},
/* Remove the last action */
undo: function() {
this.data.splice(this.data.length-1,1);
canvas.redraw();
this.restore();
},
/* Wipe the slate clean */
purge: function() {
for(var i=0;i<this.data.length;i++)
this.undo();
},
/* Export to PNG */
png: function() {
alert('This will open the image in a new window. Right-click and choose Save As to download the image.');
window.open(canvas.toDataURL('image/png'), 'Save as PNG');
}
}
/* Draw lines with this */
line = {
snap: true, // Snap to grid is enabled by default
color: 'blue', // Default color is blue
width: 2, // Default width is 2
x1: 0, y1: 0, x2: 0, y2: 0, // Default coordinates are all 0,0
/* Record our starting x,y */
start: function(x,y) {
this.x1 = this.snap_to_grid(x);
this.y1 = this.snap_to_grid(y);
},
/* Record our stopping x,y and draw */
stop: function(x,y) {
this.x2 = this.snap_to_grid(x);
this.y2 = this.snap_to_grid(y);
this.draw(this.x1,this.y1,this.x2,this.y2,'line');
},
/* Draw a line */
draw: function(x1,y1,x2,y2,type,color,width) {
/* If we don't know what type, let's assume it's a plain old line */
if(type==undefined)
type = 'line';
/* Only get the options if it's a plain old line */
if(type=='line')
this.update_options();
/* No color? It's this color! */
if(color==undefined)
ctx.strokeStyle = this.color;
else
ctx.strokeStyle = color;
/* Even skinny people have width */
if(width==undefined)
ctx.lineWidth = this.width;
else
ctx.lineWidth = width;
/* Draw the line */
ctx.beginPath(); // Set up the path
ctx.moveTo(x1,y1); // The start of the line
ctx.lineTo(x2,y2); // The end of the line
ctx.closePath(); // Close the path
ctx.stroke(); // Draw it
/* If it's a plain line, save it and clean up and guide lines */
if(type=='line') {
actions.save();
canvas.redraw();
actions.restore();
}
},
/* For drawing a handy guide line */
guide: function(x,y) {
this.update_options();
canvas.redraw();
actions.restore();
this.draw(this.x1,this.y1,this.snap_to_grid(x),this.snap_to_grid(y),'guide');
},
/* Calculate the nearest snap point (calculated by spacing) */
snap_to_grid: function(p) {
if(!this.snap)
return false;
var p2;
for(var i=p-(spacing/2);i<p+(spacing/2);i++)
if(i%spacing==0)
p2 = i;
return p2;
},
/* Get all the set options from the toolset */
update_options: function() {
if(canvas.in_restore)
return false;
this.snap = document.getElementById('snap_to_grid').checked;
this.color = document.getElementById('line_color').value;
this.width = document.getElementById('line_width').value;
}
}
/* Clear out everything */
canvas.clear = function() {
ctx.clearRect(0,0,this.width,this.height);
}
/* Redraw everything */
canvas.redraw = function() {
this.clear();
/* Prepare to draw the grid */
ctx.beginPath();
ctx.strokeStyle = 'lightblue';
ctx.lineWidth = 1;
/* Vertical rule */
for(var y=spacing;y<this.h;y=y+spacing) {
ctx.moveTo(0,y);
ctx.lineTo(this.w,y);
}
/* Horizontal rule */
for(var x=spacing;x<this.w;x=x+spacing) {
ctx.moveTo(x,0);
ctx.lineTo(x,this.h);
}
/* Draw the grid */
ctx.closePath();
ctx.stroke();
/* Restore any saved actions */
actions.restore();
}
/* When the user moves the mouse */
canvas.onmousemove = function(e) {
if(!e) var e = window.event;
var x = e.clientX;
var y = e.clientY;
/* Update the coordinates */
toolset_coord.update(x,y);
popup.show(x,y);
/* If we're drawing a line, show the guide line */
if(this.mousedown)
line.guide(x,y);
}
/* When the clicker goes down (but not back up) */
canvas.onmousedown = function(e) {
if(!e) var e = window.event;
/* Confirm it's down (handy for later) */
this.mousedown = true;
var x = e.clientX;
var y = e.clientY;
/* Set the start of the line and show the pop-up */
line.start(x,y);
popup.show(x,y);
}
/* When the clicker comes back up */
canvas.onmouseup = function(e) {
if(!e) var e = window.event;
/* We're no longer holding down */
this.mousedown = false;
var x = e.clientX;
var y = e.clientY;
/* Set the stop point and hide the pop-up */
line.stop(x,y);
popup.hide();
}
/* Show the pop-up */
popup.show = function (x,y) {
if(!canvas.mousedown)
return false;
/* Offset it from the cursor a little bit */
this.style.left = (x+30)+'px';
this.style.top = (y+30)+'px';
/* Display coordinates and distance */
this.innerHTML = x+', '+y;
this.innerHTML += ', '+this.distance(line.x1,line.y1,line.snap_to_grid(x),line.snap_to_grid(y))+"cm";
/* Show the pop-up */
this.style.display = 'block';
}
/* Use Pythagora's theorem to calculate distance */
popup.distance = function(x1,y1,x2,y2) {
var scale_in = document.getElementById('scale_in').value;
var scale_frac = document.getElementById('scale_frac').value;
var scale = parseFloat(scale_in)+parseFloat(scale_frac);
var a = x1-x2;
var b = y1-y2;
if(a<0) a *= -1;
if(b<0) b *= -1;
var retval = Math.sqrt(Math.pow(a,2)+Math.pow(b,2));
retval = Math.round(parseFloat(retval*scale/spacing)*100)/100;
return retval;
}
/* Hide the pop-up */
popup.hide = function() {
this.style.display = 'none';
}
/* Now that all functions and objects are set, draw the grid */
canvas.redraw();
}
function getDocumentPPI() {
var elem = document.createElement('div');
elem.style.width = '1in';
document.body.appendChild(elem);
var ppi = elem.offsetWidth;
//document.body.removeChild(elem);
return ppi;
}
</script>
<style type="text/css">body{margin:0;overflow:hidden;}#canvas{z-index:1;}#toolset{z-index:2;position:absolute;bottom:10px;right:10px;border:1px solid #000;background-color:#fff;font-family:sans-serif;font-size:90%;padding:10px;}#toolset p{margin:0;clear:both;line-height:2em;}#toolset p label{font-weight:bold;width:7em;float:left;display:inline-block;}#toolset p select{float:left;border:1px solid #000;color:blue;display:inline-block;}#toolset input[type=checkbox]{position:relative;top:0.5em;float:left;display:inline-block;}#popup{display:none;position:absolute;top:-100px;left:-100px;z-index:100;background-color:#fff;border:1px solid #000;padding:0.5em;}</style>
</head>
<body onload="BodyLoad();">
<script>
var ppi = getDocumentPPI();
</script>
<canvas id="canvas"></canvas>
<div id="popup"></div>
<div id="toolset">
<p>
<button onclick="actions.undo()">Undo</button>
<button onclick="actions.purge()">Start Over</button>
<button onclick="actions.png()">Save</button>
</p>
<p>
<label>Coordinates</label>
<span id="coord">0,0</span>
</p>
<p>
<label>Snap to grid</label>
<input type="checkbox" id="snap_to_grid" checked />
</p>
<p>
<label>Line Color</label>
<select id="line_color">
<option>Black</option>
<option>Red</option>
<option>Orange</option>
<option>Yellow</option>
<option>Green</option>
<option selected>Blue</option>
<option>Purple</option>
</select>
</p>
<p>
<label>Line Width</label>
<select id="line_width">
<option>1</option>
<option selected>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
<option>10</option>
</select>
</p>
<p>
<label>Scale</label>
<select id="scale_in">
<option>0</option>
<option selected>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
<option>10</option>
<option>11</option>
<option>12</option>
</select>
<span style="float: left">.</span>
<select id="scale_frac">
<option>0</option>
<option value=".25">25</option>
<option value=".5">5</option>
<option value=".75">75</option>
</select>
&quot;
</p>
<p>
<label>Graph Rule</label>
<select id="spacing" onchange="spacing=(this.value*72)/2.5;canvas.redraw()">
<option value=".25">2.5mm</option>
<option value=".5">5mm</option>
<option value=".75">7.5mm</option>
<option value="1">10mm</option>
</select>
</p>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment