+Shapes, +Background, +Fill/Stroke, +Line Join

This commit is contained in:
Mahdi Dibaiee
2014-02-16 18:00:45 +03:30
parent c65a36f109
commit 7eff240187
202 changed files with 1561 additions and 349 deletions

239
Mobile/js/functions-m.js Executable file
View File

@ -0,0 +1,239 @@
"use strict";
/*** ESSENTIALS ***/
function sizeAndPos() {
var data = c.getImageData(0,0, $c.width(), $c.height());
var w = $(window).width(),
h = $(window).height() - 53;
$c.attr('width', w * window.devicePixelRatio);
$c.attr('height',h * window.devicePixelRatio);
$c.css({
'width' : w,
'height' : h
});
c.clearRect(0,0, width(), height());
c.putImageData(data, 0, 0);
}
function relative(x,y, el) {
var el = el || $c[0];
return {
x : x*window.devicePixelRatio - el.offset().left,
y : (y - 53) * window.devicePixelRatio - el.offset().top
}
}
function threshold(x1, y1, x2, y2, threshold) {
var tr = threshold || 5;
if( x1 <= x2 + tr && x1 >= x2 - tr && y1 <= y2 + tr && y1 >= y2 - tr ) return true;
return false;
}
function draw(x1, y1, x2, y2, opts, overlay) {
opts = opts || {};
var c = window.c;
if( overlay ) var c = window.o;
c.beginPath();
if( settings.type == 'eraser' ) c.globalCompositeOperation = 'destination-out';
else c.globalCompositeOperation = opts.composite || settings.composite;
c.lineCap = opts.lineCap || settings.lineCap;
c.lineJoin = opts.lineJoin || settings.lineJoin;
c.strokeStyle = opts.color || settings.color;
c.fillStyle = opts.color || settings.color;
c.lineWidth = ( opts.lineWidth || settings.lineWidth ) / 10;
c.moveTo(x1, y1);
c.lineTo(x2, y2);
if( !opts.noStroke ) c.stroke();
if( opts.fill ) c.fill();
}
function shape(opts, overlay) {
if(overlay) var c = window.o;
else var c = window.c;
c.beginPath();
c.fillStyle = opts.color || settings.color;
switch(opts.type) {
case 'circle': {
c.arc(opts.x, opts.y, opts.radius, 0, 2*Math.PI);
break;
}
case 'rectangle': {
c.rect(opts.x, opts.y, opts.width, opts.height);
break;
}
case 'square': {
c.rect(opts.x, opts.y, opts.width, opts.width);
break;
}
case 'triangle': {
c.fillStyle = opts
c.moveTo(opts.x1, opts.y1);
c.lineTo(opts.x2, opts.y2);
c.lineTo(opts.x3, opts.y3);
c.lineTo(opts.x1, opts.y1);
}
}
c.fill();
}
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, width(), 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;
}
}
function width() {
return +$c.attr('width');
}
function height() {
return +$c.attr('height');
}
function dataToBlob(data) {
var binary = atob(data.split(',')[1]), array = [];
var type = data.split(',')[0].split(':')[1].split(';')[0];
for(var i = 0; i < binary.length; i++) array.push(binary.charCodeAt(i));
return new Blob([new Uint8Array(array)], {type: type});
}
/*** END ***/
function startPoint(x, y) {
// If no previous point exists, make the first one.
if( !points.length ) points.push({x: x, y: y, type: '', start: {x: x, y: y}});
var old = points[points.length-1],
start = old.start,
current = {
x : x,
y : y,
start : old.start || {x: x, y: y},
type : settings.type
}
// Line
if( old.type !== 'line' && current.type == 'line' ) {
window.o.beginPath();
window.o.fillStyle = 'red';
window.o.arc(x,y, 3, 0, 2*Math.PI);
window.o.fill();
}
if( old.type == 'line' && current.type == 'line' ) {
if( points[points.indexOf(old)-1].type !== 'line' ) {
o.clearRect(old.x-3, old.y-3, 6, 6, true);
draw(old.x, old.y, x, y);
} else
draw(old.x, old.y, x, y);
}
// Shapes
if( old.type !== 'shape' && current.type == 'shape' ) {
settings.shape.
}
var thresholds = window.mobile ? [10, 5] : [5, 2];
if( points.length > 1 && ((start && threshold(start.x, start.y, x, y, thresholds[0])) || threshold(old.x, old.y, x, y, thresholds[1])) ) {
window.active = false;
points[points.length-1].type = '';
points[points.length-1].start = undefined;
return;
}
points.push(current);
}
function drawPoint(x,y) {
var capture = points[points.length-1];
switch(capture.type) {
case 'eraser': {
capture.type = 'pen';
}
case 'pen': {
draw(capture.x, capture.y, x, y);
var current = {
x : x,
y : y,
start : capture.start,
type : capture.type
}
points.push(current);
break;
}
case 'sketch': {
draw(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, settings.connectTelorance)) {
var x = points[i].x - current.x,
y = points[i].y - current.y;
var w = settings.lineWidth/20 > 0.2 ? settings.lineWidth/20 : 0.2;
draw(points[i].x - x*0.2, points[i].y - y*0.2, current.x + x*0.2, current.y + y*0.2, {strokeStyle: 'rgba(0,0,0,0.4)', lineWidth: w})
}
}
break;
}
case 'fur': {
draw(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, settings.connectTelorance)) {
var x = points[i].x - current.x,
y = points[i].y - current.y;
var l = settings.furLength / 100 || 0.2;
var w = settings.lineWidth/20 > 0.2 ? settings.lineWidth/20 : 0.2;
draw(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: w})
}
}
break;
}
}
}

0
Mobile/js/functions.css Normal file → Executable file
View File

202
Mobile/js/functions.js Normal file → Executable file
View File

@ -12,15 +12,16 @@ function sizeAndPos() {
'width' : w,
'height' : h
});
c.clearRect(0,0, width(), height());
c.clear();
c.putImageData(data, 0, 0);
}
function relative(x,y, el) {
var el = el || $c[0];
var el = el || $c,
offset = el.offset();
return {
x : x*window.devicePixelRatio - el.offset().left,
y : (y - 53) * window.devicePixelRatio - el.offset().top
x : (x - offset.left) *window.devicePixelRatio,
y : (y - offset.top) * window.devicePixelRatio
}
}
@ -32,8 +33,8 @@ function threshold(x1, y1, x2, y2, threshold) {
function draw(x1, y1, x2, y2, opts, overlay) {
opts = opts || {};
var c = window.c;
if( overlay ) var c = window.o;
else var c = window.c;
c.beginPath();
if( settings.type == 'eraser' ) c.globalCompositeOperation = 'destination-out';
else c.globalCompositeOperation = opts.composite || settings.composite;
@ -44,41 +45,76 @@ function draw(x1, y1, x2, y2, opts, overlay) {
c.lineWidth = ( opts.lineWidth || settings.lineWidth ) / 10;
c.moveTo(x1, y1);
c.lineTo(x2, y2);
if( !opts.noStroke ) c.stroke();
if( opts.fill ) c.fill();
if( !opts.noStroke || settings.noStroke ) c.stroke();
if( opts.fill || settings.fill ) c.fill();
}
function shape(opts, overlay) {
if(overlay) var c = window.o;
else var c = window.c;
function mark(x, y) {
var o = window.o;
o.beginPath();
o.fillStyle = 'red';
o.arc(x,y, 3, 0, 2*Math.PI);
o.fill();
}
function erase(x1, y1, x2, y2, opts) {
var opts = opts || {};
var c = window.c;
c.beginPath();
c.fillStyle = opts.color || settings.color;
switch(opts.type) {
case 'circle': {
c.arc(opts.x, opts.y, opts.radius, 0, 2*Math.PI);
break;
}
case 'rectangle': {
c.rect(opts.x, opts.y, opts.width, opts.height);
break;
}
case 'square': {
c.rect(opts.x, opts.y, opts.width, opts.width);
break;
}
case 'triangle': {
c.fillStyle = opts
c.moveTo(opts.x1, opts.y1);
c.lineTo(opts.x2, opts.y2);
c.lineTo(opts.x3, opts.y3);
c.lineTo(opts.x1, opts.y1);
}
}
c.fill();
c.lineWidth = ( opts.lineWidth || settings.lineWidth ) / 10;
c.globalCompositeOperation = 'source-out';
c.moveTo(x1, y1);
c.lineTo(x2, y2);
window.points = window.points.filter(function(e, i) {
if(!threshold(e.x, e.y, x1, y1, c.lineWidth) &&
!threshold(e.x, e.y, x2, y2, c.lineWidth) ) return true;
return false;
})
}
function line(x, y, opts) {
var opts = opts || {};
var o = window.o;
o.beginPath();
o.lineCap = opts.lineCap || settings.lineCap;
o.lineJoin = opts.lineJoin || settings.lineJoin;
o.strokeStyle = opts.color || settings.color;
o.fillStyle = opts.color || settings.color;
o.lineWidth = ( opts.lineWidth || settings.lineWidth ) / 10;
var last = settings.drawingLine.length-1;
o.moveTo(settings.drawingLine[last].x, settings.drawingLine[last].y);
o.lineTo(x,y);
settings.drawingLine.push({
x: x,
y: y
})
o.stroke();
if( opts.fill || settings.fill ) o.fill();
}
function finishLine(opts) {
var opts = opts || {};
var c = window.c;
o.clear();
c.beginPath();
c.strokeStyle = opts.color || settings.color;
c.fillStyle = opts.color || settings.color;
c.lineWidth = ( opts.lineWidth || settings.lineWidth ) / 10;
c.lineJoin = opts.lineJoin || settings.lineJoin;
c.lineCap = opts.lineJoin || settings.lineJoin;
c.moveTo(settings.drawingLine[0].x, settings.drawingLine[0].y);
for( var i = 1, len = settings.drawingLine.length; i < len; i++ ) {
c.lineTo(settings.drawingLine[i].x, settings.drawingLine[i].y);
}
if( settings.stroke ) c.stroke();
if( settings.fill ) c.fill();
settings.drawingLine = [];
window.points.history.push({
data: c.getImageData(0, 0, width(), height()),
points: window.points.slice(0)
})
window.points.history.last = window.points.history.length-1;
}
function undo() {
var history = window.points.history;
@ -89,7 +125,7 @@ function undo() {
window.points.history = history;
window.points.history.last = history.last-1;
} else {
c.clearRect(0,0, width(), height());
c.clear();
window.points = [];
window.points.history = history;
window.points.history.last = 0;
@ -139,26 +175,27 @@ function startPoint(x, y) {
start : old.start || {x: x, y: y},
type : settings.type
}
// Line
if( old.type !== 'line' && current.type == 'line' ) {
window.o.beginPath();
window.o.fillStyle = 'red';
window.o.arc(x,y, 3, 0, 2*Math.PI);
window.o.fill();
mark(x, y);
settings.drawingLine.push({
x: x,
y: y
})
}
if( old.type == 'line' && current.type == 'line' ) {
if( points[points.indexOf(old)-1].type !== 'line' ) {
o.clearRect(old.x-3, old.y-3, 6, 6, true);
draw(old.x, old.y, x, y);
} else
draw(old.x, old.y, x, y);
o.clear();
}
line(x, y);
}
// Shapes
if( old.type !== 'shape' && current.type == 'shape' ) {
settings.shape.
if( current.type == 'shape' ) {
settings.shapeStart = current;
}
var thresholds = window.mobile ? [10, 5] : [5, 2];
@ -166,6 +203,7 @@ function startPoint(x, y) {
window.active = false;
points[points.length-1].type = '';
points[points.length-1].start = undefined;
finishLine();
return;
}
points.push(current);
@ -176,9 +214,9 @@ function drawPoint(x,y) {
switch(capture.type) {
case 'eraser': {
capture.type = 'pen';
erase(capture.x, capture.y, x, y);
}
case 'pen': {
case 'pencil': {
draw(capture.x, capture.y, x, y);
var current = {
@ -234,6 +272,74 @@ function drawPoint(x,y) {
}
break;
}
case 'shape': {
o.clear();
o.beginPath();
o.fillStyle = settings.color;
o.strokeStyle = settings.color;
o.lineWidth = settings.lineWidth / 20;
var start = settings.shapeStart;
switch(settings.shape) {
case 'circle': {
var di = Math.abs(x - start.x);
o.arc(start.x, start.y, di, 0, 2*Math.PI);
settings.comShape = {
type: 'circle',
x: start.x,
y: start.y,
radius: di
}
break;
}
case 'rectangle': {
var w = x - start.x;
var h = y - start.y;
o.rect(start.x, start.y, w, h);
settings.comShape = {
type: 'rectangle',
x: start.x,
y: start.y,
w: w,
h: h
}
break;
}
case 'square': {
var w = x - start.x;
o.rect(start.x, start.y, w, w);
settings.comShape = {
type: 'rectangle',
x: start.x,
y: start.y,
w: w,
h: w
}
break;
}
case 'triangle': {
var dix = (x - start.x)/2;
var diy = (y - start.y)/2;
o.moveTo(start.x + dix, start.y);
o.lineTo(x, y);
o.lineTo(start.x, y);
o.lineTo(start.x + dix, start.y);
settings.comShape = {
type: 'triangle',
start: {
x: start.x,
y: start.y
},
x: x,
y: y,
dix: dix,
diy: diy
}
}
}
if( settings.fill ) o.fill();
if( settings.stroke ) o.stroke();
break;
}
}
}

0
Mobile/js/less-1.5.0.min.js vendored Normal file → Executable file
View File

0
Mobile/js/libs/color-picker-touch.js Normal file → Executable file
View File

0
Mobile/js/libs/color-picker.js Normal file → Executable file
View File

0
Mobile/js/libs/mobilebrowsers.js Normal file → Executable file
View File

0
Mobile/js/libs/stack.js Normal file → Executable file
View File

0
Mobile/js/libs/touch.js Normal file → Executable file
View File

0
Mobile/js/libs/yepnope.min.js vendored Normal file → Executable file
View File

0
Mobile/js/libs/zepto.min.js vendored Normal file → Executable file
View File

31
Mobile/js/main.js Normal file → Executable file
View File

@ -3,8 +3,12 @@
$(document).ready(function() {
window.c = $('canvas')[0].getContext('2d');
window.o = $('canvas')[1].getContext('2d');
window.c.clear = window.o.clear = function() {
this.clearRect(0, 0, width(), height());
}
window.settings = {
stroke: true,
fill: false,
lineWidth : 2,
color : 'black',
type: 'sketch',
@ -12,7 +16,12 @@ $(document).ready(function() {
lineJoin: 'round',
furLength: 5,
connectTelorance: 40,
composite: 'source-over'
composite: 'source-over',
shape: 'circle',
shapeStart: {},
comShape: {},
drawingLine: [],
version: 1.2
};
window.points = [];
window.$c = $('canvas');
@ -20,19 +29,21 @@ $(document).ready(function() {
window.points.history.last = 0;
sizeAndPos();
//$(window).resize(sizeAndPos);
$('.color-picker').change(function() {
var c = $(this).find('.color').val();
settings.color = c;
$('#setcolor span').html(c);
var caller = $(this).parent().attr('data-caller');
settings[caller] = c;
$('#set' + caller + ' span').html(c);
if( caller == 'bg' ) {
$c.first().css('background', c);
}
})
$('.color').val('#000000');
/*yepnope({
test: window.mobile,
yep : ['js/libs/touch.js', 'js/mobile.js', 'js/libs/color-picker-touch.js'],
nope: ['js/desktop.js', 'js/libs/color-picker.js']
})*/
if( localStorage.getItem('sawTips') != settings.version ) {
$('.tour').removeClass('hidden');
localStorage.setItem('sawTips', settings.version);
}
})

0
Mobile/js/mobile.css Normal file
View File

80
Mobile/js/mobile.js Normal file → Executable file
View File

@ -43,7 +43,7 @@ window.save = function() {
break;
}
case 'current color': {
c.fillStyle = settings.color;
c.fillStyle = settings.bg;
c.globalCompositeOperation = 'destination-over';
c.fillRect(0, 0, width(), height());
c.globalCompositeOperation = settings.composite;
@ -109,7 +109,7 @@ window.load = function() {
$(this).attr('aria-selected', 'true');
})
})
$('#pro').click(function() {
$('#pro').tap(function() {
$('#save ol:nth-of-type(2) li').each(function() {
if( $(this).find('span').html() !== 'Transparent' ) {
$(this).addClass('hidden');
@ -118,7 +118,7 @@ window.load = function() {
else $(this).attr('aria-selected', 'true');
})
})
$('#exp').click(function() {
$('#exp').tap(function() {
$('#save ol:nth-of-type(2) li').removeClass('hidden');
})
$c.last().on('touchstart', function(e) {
@ -133,10 +133,40 @@ window.load = function() {
window.active = false;
if( settings.type == 'eraser' ) return;
if( settings.type == 'shape' ) {
var s = settings.comShape;
o.clear();
c.beginPath();
c.fillStyle = settings.color;
c.strokeStyle = settings.color;
c.lineWidth = settings.lineWidth / 20;
switch(s.type) {
case 'circle': {
c.arc(s.x, s.y, s.radius, 0, 2*Math.PI);
break;
}
case 'rectangle': {
c.rect(s.x, s.y, s.w, s.h)
break;
}
case 'triangle': {
c.moveTo(s.start.x + s.dix, s.start.y);
c.lineTo(s.x, s.y);
c.lineTo(s.start.x, s.y);
c.lineTo(s.start.x + s.dix, s.start.y);
break;
}
}
if( settings.fill ) c.fill();
if( settings.stroke ) c.stroke();
}
if( settings.type == 'line' ) return;
if(window.points.history.last < window.points.history.length-1) {
window.points.history.splice(window.points.history.last+1);
}
window.points.history.push({
data: c.getImageData(0, 0, width(), height()),
points: window.points.slice(0)
@ -147,6 +177,7 @@ window.load = function() {
window.active = false;
points[points.length-1].type = '';
points[points.length-1].start = undefined;
finishLine();
}
})
@ -155,23 +186,23 @@ window.load = function() {
var $single = $('form[data-type="value-selector"].single');
$single.find('li').tap(function(e) {
e.preventDefault();
$(this).parent().find('li[aria-selected]').removeAttr('aria-selected');
$(this).attr('aria-selected', 'true');
var key = $(this).parents('form').attr('id'),
value = $(this).find('label span').html().toLowerCase();
value = $(this).find('label span').html().toLowerCase(),
target = $(this).attr('data-target');
window.settings[key] = value;
$('button[id="set' + key + '"] span').html(value[0].toUpperCase() + value.substr(1));
$('#menu div.options > div').addClass('hidden');
$('#menu div.options > .general, #menu div.options > .'+value).removeClass('hidden');
if( target ) {
$('#menu div.options > div').addClass('hidden');
$('#menu div.options > .general, #menu div.options > .'+target).removeClass('hidden');
}
$(this).parents('form').addClass('hidden');
})
$single.find('button').tap(function(e) {
$single.submit(function(e) {
e.preventDefault();
$(this).parents('form').addClass('hidden');
$(this).addClass('hidden');
})
// Confirm
@ -180,11 +211,11 @@ window.load = function() {
$confirm.each(function() {
$(this).find('li').click(function(e) {
$(this).find('li').tap(function(e) {
$(this).parent().find('li[aria-selected]').removeAttr('aria-selected');
$(this).attr('aria-selected', 'true');
})
$(this).find('button').last().click(function(e) {
$(this).find('button').last().tap(function(e) {
e.preventDefault();
var v = $(this).parents('form').attr('id');
$(this).parents('form').find('h1').each(function(i) {
@ -198,7 +229,7 @@ window.load = function() {
$(this).parents('form').addClass('hidden');
window[v]();
})
$(this).find('button').first().click(function(e) {
$(this).find('button').first().tap(function(e) {
e.preventDefault();
$(this).parents('form').addClass('hidden');
})
@ -210,9 +241,11 @@ window.load = function() {
var $btn = $('button[id^="set"]');
$btn.each(function() {
var target = /set(.*)/.exec($(this).attr('id'))[1];
if( target == 'color' ) {
// Exception for Color
if( target == 'color' || target == 'bg' ) {
return $(this).tap(function() {
$('.picker').removeClass('hidden');
$('.picker').attr('data-caller', target);
})
}
$(this).tap(function(e) {
@ -246,6 +279,21 @@ window.load = function() {
$(this).removeAttr('data-moving');
})
$('.fill, .stroke').tap(function() {
var s = $('.'+$(this).attr('class')).find('span');
if( s.html() == 'Yes' ) {
s.html('No');
settings[$(this).attr('class')] = false;
} else {
s.html('Yes');
settings[$(this).attr('class')] = true;
}
})
$('.close, .tour button').tap(function() {
$(this).parent().addClass('hidden');
})
// Color Picker
$('.close').tap(function() {