(function() {
var ctx = canvas.getContext('2d');
////////////////////
// Object Storage //
////////////////////
// unfortunately, localStorage on stack-snippet will throw a security exception ...
/*
// get saved from localStorage, could be from server as well
var fromStorage = function(){
var str = localStorage.getItem('objects');
if(!str) return false;
return JSON.parse(str);
};
// save to localStorage or server
var toStorage = function(){
localStorage.setItem('objects', JSON.stringify(objects));
}
*/
// ... so just show the string that could be saved on server
var toStorage = function() {
log.innerHTML = JSON.stringify(objects);
};
save.onclick = toStorage;
// initiate the objects previously stored or default one
// var objects = fromStorage() || [{...}] Once again won't work in stack-snippets
var objects = [
{type:'rect', x:900, y:360, width:100, height:100, color:'blue'},
{type:'circle', x:150, y:60, width:72, height:72, color:'red'},
{type:'image', url:"http://lorempixel.com/500/500", x:500, y:250, width: 300, height:300}
];
// initialise our canvas
var init = function() {
// set the canvas' size and get the ratio
setSize(sizes[0]);
// check if there are image to load
for (var i = 0; i < objects.length; i++) {
if (objects[i].type === 'image') {
imagesToLoad++;
loadImage(objects[i]);
}
}
// if there's none, draw already
if (!imagesToLoad) draw();
};
// we only pass the desired width since we'll get the height from the ratio
var setSize = function(width) {
// set the canvas width
canvas.width = width;
// get the ratio of the current width divided by the desired one
// store it in the canvas element so we can use it after in mouse events
var ratio = canvas.ratio = canvas.width / 1200;
// set our canvas height
canvas.height = ratio * 630;
// set the context scale to the ratio so we don't care about it while drawing
ctx.scale(ratio, ratio);
}
// the drawing part
var draw = function() {
// clear the canvas at the default size since we changed the context's scale
ctx.clearRect(0, 0, 1200, 630);
// iterate through our objects array
for (var i = 0; i < objects.length; i++) {
var obj = objects[i];
// set the current color to the one of the object
ctx.fillStyle = obj.color;
// do different drawing operations based on object's type
switch (obj.type) {
case 'rect':
ctx.fillRect(obj.x, obj.y, obj.width, obj.height);
break;
case 'circle':
ctx.beginPath();
ctx.arc(obj.x + obj.width / 2, obj.y + obj.width / 2, obj.width / 2, Math.PI * 2, 0);
ctx.fill();
break;
case 'image':
ctx.drawImage(obj.img, obj.x, obj.y, obj.width, obj.height);
break;
}
}
};
var imagesToLoad = 0;
// a function to load all our image resources
var loadImage = function(obj) {
var img = new Image();
img.onload = function() {
obj.img = this;
if (!--imagesToLoad)
draw();
}
img.src = obj.url;
};
//////////////////
// mouse Events //
//////////////////
var activeObjects;
var mousedownHandler = function(e) {
var rect = canvas.getBoundingClientRect();
var x = (e.clientX - rect.left) / canvas.ratio;
var y = (e.clientY - rect.top) / canvas.ratio;
activeObjects = getActiveObjects(x, y);
};
var mouseupHandler = function(e) {
// we stopped dragging, reset the activeObjects array
activeObjects = null;
}
var mousemoveHandler = function(e) {
// if there is no object being dragged
if (!activeObjects) return;
// x and y coordinates have to be scaled by our actual ratio
var rect = canvas.getBoundingClientRect();
var x = (e.clientX - rect.left) / canvas.ratio;
var y = (e.clientY - rect.top) / canvas.ratio;
// iterate through all active objects
for (var i = 0; i < activeObjects.length; i++) {
// and update their position
update(activeObjects[i], x, y);
}
};
var getActiveObjects = function(x, y) {
var arr = [];
for (var i = 0; i < objects.length; i++) {
var obj = objects[i];
if (obj.x < x && obj.x + obj.width > x && obj.y < y && obj.y + obj.height > y)
arr.push(obj);
}
if (!arr.length) return null;
else return arr;
};
var update = function(obj, x, y) {
obj.x = x - (obj.width / 2);
obj.y = y - (obj.height / 2);
draw();
}
canvas.addEventListener('mousedown', mousedownHandler);
canvas.addEventListener('mouseup', mouseupHandler);
canvas.addEventListener('mousemove', mousemoveHandler);
/////////////////////////////
// Button events (for demo) //
/////////////////////////////
// store different sizes for our canvas
var sizes = [300, 200, 600, 3000];
var currentSize = 0;
resize.onclick = function() {
// iterate through the sizes array
setSize(sizes[++currentSize % sizes.length]);
draw();
};
// randomise our objects shapes and position
rand.onclick = function() {
for (var i = 0; i < objects.length; i++) {
var obj = objects[i];
obj.x = Math.random() * 1000;
obj.y = Math.random() * 500;
obj.width = Math.random() * 500;
obj.height = (obj.type === 'circle') ? obj.width : Math.random() * 500;
}
draw();
}
// Let's go !
init();
})();
canvas {
border: 1px solid
}
<button id="resize">resize canvas</button>
<button id="save">save</button>
<button id="rand">randomize</button><br>
<canvas id="canvas"></canvas>
<br><p id="log"></p>