Undo/Redo

This commit is contained in:
Mahdi Dibaiee 2014-02-02 23:46:28 +03:30
parent 9f427204ac
commit 17a8409a68
7 changed files with 127 additions and 30 deletions

View File

@ -10,8 +10,15 @@ html, body {
outline: none; outline: none;
} }
div#container {
position: absolute;
}
canvas { canvas {
border: 1px solid gray; border: 1px solid gray;
position: absolute;
top: 0;
left: 0;
} }
header { header {

BIN
img/icons/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
img/icons/demo1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -14,7 +14,10 @@
<button id='menu'></button> <button id='menu'></button>
</header> </header>
<div id='container'>
<canvas></canvas> <canvas></canvas>
<canvas></canvas>
</div>
<script src='js/libs/zepto.min.js'></script> <script src='js/libs/zepto.min.js'></script>
<script src='js/functions.js'></script> <script src='js/functions.js'></script>

View File

@ -6,11 +6,8 @@ function sizeAndPos() {
var data = c.getImageData(0,0, $c.width(), $c.height()); var data = c.getImageData(0,0, $c.width(), $c.height());
var w = $(window).width(), var w = $(window).width(),
h = $(window).height(); h = $(window).height();
$c.css({'margin-left': w * .05, $c.attr('width', w);
'margin-top': h * .05 $c.attr('height',h - 50);
})
$c.attr('width', w * .9);
$c.attr('height',h * .9 - 50);
c.clearRect(0,0, $c.width(), $c.height()); c.clearRect(0,0, $c.width(), $c.height());
c.putImageData(data, 0, 0); c.putImageData(data, 0, 0);
} }
@ -28,8 +25,10 @@ function threshold(x1, y1, x2, y2, threshold) {
return false; return false;
} }
function line(x1, y1, x2, y2, opts) { function line(x1, y1, x2, y2, opts, overlay) {
opts = opts || {}; opts = opts || {};
var c = window.c;
if( overlay ) var c = window.o;
c.beginPath(); c.beginPath();
c.lineCap = opts.lineCap || settings.lineCap; c.lineCap = opts.lineCap || settings.lineCap;
c.lineJoin = opts.lineJoin || settings.lineJoin; c.lineJoin = opts.lineJoin || settings.lineJoin;
@ -40,13 +39,47 @@ function line(x1, y1, x2, y2, opts) {
c.stroke(); c.stroke();
} }
function erase(x1, y1, x2, y2, overlay) {
var c = window.c;
if( overlay ) var c = window.o;
c.clearRect(x1, y1, x2 - x1, y2 - y1);
}
function undo() {
var history = window.points.history;
if( history.last > 1 ) {
var step = history[history.last-1];
c.putImageData(step.data, 0, 0);
window.points = step.points.slice(0);
window.points.history = history;
window.points.history.last = history.last-1;
} else {
c.clearRect(0,0, $c.width(), $c.height());
window.points = [];
window.points.history = history;
window.points.history.last = 0;
}
}
function redo() {
var history = window.points.history;
if( history.last < history.length-1 ) {
var step = history[history.last+1];
c.putImageData(step.data, 0, 0);
window.points = step.points.slice(0);
window.points.history = history;
window.points.history.last = history.last+1;
}
}
/*** END ***/ /*** END ***/
function startPoint(x, y) { function startPoint(x, y) {
// If not previous point exists, make the first one. // If no previous point exists, make the first one.
if( !points.length ) points.push({x: x, y: y, type: settings.type, start: {x: x, y: y}}); if( !points.length ) points.push({x: x, y: y, type: '', start: {x: x, y: y}});
var old = points[points.length-1], var old = points[points.length-1],
start = old.start, start = old.start,
@ -56,10 +89,12 @@ function startPoint(x, y) {
start : old.start || {x: x, y: y}, start : old.start || {x: x, y: y},
type : settings.type type : settings.type
} }
// Just draws a circle if( old.type !== 'line' && current.type == 'line' ) {
line(x,y,x,y); line(x,y,x,y, {lineWidth: 5, strokeStyle: 'red'}, true);
}
if( old.type == 'line' ) { if( old.type == 'line' ) {
if( points[points.indexOf(old)-1].type !== 'line' ) erase(old.x-5, old.y-5, old.x+5, old.y+5, true);
line(old.x, old.y, x, y); line(old.x, old.y, x, y);
} }
@ -70,6 +105,10 @@ function startPoint(x, y) {
return; return;
} }
if(current.type == 'ribbon') {
settings.ribbonTimes = 1;
}
points.push(current); points.push(current);
} }
@ -101,7 +140,7 @@ function drawPoint(x,y) {
points.push(current); points.push(current);
for( var i = 0, len = points.length-1; i < len; i++ ) { for( var i = 0, len = points.length-1; i < len; i++ ) {
if( threshold(points[i].x, points[i].y, current.x, current.y, 40)) { if(threshold(points[i].x, points[i].y, current.x, current.y, 40)) {
var x = points[i].x - current.x, var x = points[i].x - current.x,
y = points[i].y - current.y; y = points[i].y - current.y;
@ -110,7 +149,26 @@ function drawPoint(x,y) {
} }
break; break;
} }
case 'fur': {
line(capture.x, capture.y, x, y);
var current = {
x : x,
y : y,
start : capture.start,
type : capture.type
}
points.push(current);
for( var i = 0, len = points.length-1; i < len; i++ ) {
if(threshold(points[i].x, points[i].y, current.x, current.y, 40)) {
var x = points[i].x - current.x,
y = points[i].y - current.y;
var l = settings.furLength || 0.2;
line(points[i].x + x*l, points[i].y + y*l, current.x - x*l, current.y - y*l, {strokeStyle: 'rgba(0,0,0,0.4)', lineWidth: settings.lineWidth/2})
}
}
break;
}
} }
} }

View File

@ -2,46 +2,49 @@
$(document).ready(function() { $(document).ready(function() {
window.c = $('canvas')[0].getContext('2d'); window.c = $('canvas')[0].getContext('2d');
window.o = $('canvas')[1].getContext('2d');
window.settings = { window.settings = {
lineWidth : 0.2, lineWidth : 0.2,
strokeStyle : 'black', strokeStyle : 'black',
type: 'sketch', type: 'sketch',
lineCap: 'round', lineCap: 'round',
lineJoin: 'round' lineJoin: 'round',
ribbonEnd: 50,
ribbonTurn : 0
}; };
window.points = []; window.points = [];
window.$c = $('canvas'); window.$c = $('canvas');
window.points.history = [{ data: c.createImageData($c.width(), $c.height()), points: []}];
sizeAndPos(); sizeAndPos();
$(window).resize(sizeAndPos); $(window).resize(sizeAndPos);
$c.bind('mousedown', function(e) { $c.last().bind('mousedown touchstart', function(e) {
e.preventDefault(); e.preventDefault();
if( e.changedTouches ) e = e.changedTouches[0];
var xy = relative(e.pageX, e.pageY); var xy = relative(e.pageX, e.pageY);
startPoint(xy.x, xy.y); startPoint(xy.x, xy.y);
window.active = true; window.active = true;
}).bind('mousemove', function(e) { }).bind('mousemove touchmove', function(e) {
e.preventDefault(); e.preventDefault();
if (!window.active || settings.type == 'line') return; if (!window.active || settings.type == 'line') return;
if( e.changedTouches ) e = e.changedTouches[0];
var xy = relative(e.pageX, e.pageY); var xy = relative(e.pageX, e.pageY);
drawPoint(xy.x, xy.y); drawPoint(xy.x, xy.y);
}).bind('mouseup touchend', function(e) { }).bind('mouseup touchend', function(e) {
e.preventDefault(); e.preventDefault();
window.active = false; window.active = false;
}).bind('touchstart', function(e) {
e.preventDefault(); if(window.points.history.last < window.points.history.length-1) {
var touch = e.changedTouches[0]; window.points.history.splice(window.points.history.last+1);
var xy = relative(touch.pageX, touch.pageY); }
startPoint(xy.x, xy.y);
window.active = true; window.points.history.push({
}).bind('touchmove', function(e) { data: c.getImageData(0, 0, $c.width(), $c.height()),
e.preventDefault(); points: window.points.slice(0)
if(!window.active || settings.type =='line') return; })
var touch = e.changedTouches[0]; window.points.history.last = window.points.history.length-1;
var xy = relative(touch.pageX, touch.pageY);
drawPoint(xy.x, xy.y);
window.active = true;
}) })
}) })

26
manifest.webapp Normal file
View File

@ -0,0 +1,26 @@
{
"name": "Sketchy",
"description": "Free Sketch/Paint app",
"version": 1,
"launch_path": "/index.html",
"icons": {
"16": "/images/logo16.png",
"32": "/images/logo32.png",
"48": "/images/logo48.png",
"60": "/images/logo60.png",
"64": "/images/logo64.png",
"90": "/images/logo90.png",
"120": "/images/logo120.png",
"128": "/images/logo128.png"
},
"developer": {
"name": "Mahdi Dibaiee",
"url": "https://twitter.com/mdibaiee"
},
"locales": {
"fa": {
"name": "Sketchy",
"description": "برنامه‌ی رایگان طراحی/نقاشی"
}
}
}