0
0
mirror of https://github.com/Doodle3D/doodle3d-client.git synced 2024-11-15 23:27:57 +01:00
doodle3d-client/js/canvasDrawing.js

489 lines
14 KiB
JavaScript
Raw Normal View History

2013-12-20 16:31:41 +01:00
/*
* This file is part of the Doodle3D project (http://doodle3d.com).
*
* Copyright (c) 2013, Doodle3D
* This software is licensed under the terms of the GNU GPL v2 or later.
* See file LICENSE.txt or visit http://www.gnu.org/licenses/gpl.html for full license details.
*/
2013-07-26 22:39:28 +02:00
/* * * * * * * * * *
*
* VARS
*
* * * * * * * * * */
var preview;
var previewCtx;
var svgPathRegExp = /[LM]\d* \d*/ig;
var svgPathParamsRegExp = /([LM])(\d*) (\d*)/;
var dragging = false;
var $canvas, canvas, ctx;
var canvasWidth, canvasHeight;
2013-07-26 22:39:28 +02:00
var drawCanvas;
var drawCanvasTopLeftCoords = [0, 0];
var doodleBounds = [-1, -1, -1, -1]; // left, top, right, bottom
// var doodleScaleVals = [[0, 0], [1.0, 1.0]]; // [ [x, y], [scaleX, scaleY] ]
var doodleTransform = [0, 0, 1.0, 1.0]; // [ x, y, scaleX, scaleY ]
var _points = [];
var prevCountingTime = 0;
var movementCounter = 0;
var drawVariableLineWeight = false; // set to true to have the momentum of the mouse/touch movement result in larger/smaller strokes
var lineweight = 2;
var isModified = false;
2013-07-26 22:39:28 +02:00
/* * * * * * * * * *
*
* INIT
*
* * * * * * * * * */
function initDoodleDrawing() {
2014-01-17 16:28:56 +01:00
//console.log("f:initDoodleDrawing()");
2013-07-26 22:39:28 +02:00
$canvas = $("#mycanvas");
canvas = $canvas[0];
ctx = canvas.getContext('2d');
canvasWidth = canvas.width;
canvasHeight = canvas.height;
//*
//TODO make these jquery eventhandlers (works for all)
2013-07-26 22:39:28 +02:00
if (!canvas.addEventListener) {
canvas.attachEvent('onmousedown',onCanvasMouseDown);
canvas.attachEvent('onmousemove',onCanvasMouseMove);
canvas.attachEvent('onmouseup',onCanvasMouseUp);
canvas.attachEvent('ontouchstart',onCanvasTouchDown);
canvas.attachEvent('ontouchmove',onCanvasTouchMove);
canvas.attachEvent('ontouchend',onCanvasTouchEnd);
document.body.attachEvent('ontouchmove',prevent);
} else {
canvas.addEventListener('mousedown',onCanvasMouseDown,false);
canvas.addEventListener('mousemove',onCanvasMouseMove,false);
canvas.addEventListener('mouseup',onCanvasMouseUp,false);
canvas.addEventListener('touchstart',onCanvasTouchDown,false);
canvas.addEventListener('touchmove',onCanvasTouchMove,false);
canvas.addEventListener('touchend',onCanvasTouchEnd,false);
if (!debugMode) document.body.addEventListener('touchmove',prevent,false);
2013-07-26 22:39:28 +02:00
}
//*/
2013-07-26 22:39:28 +02:00
// drawCanvas = $(".drawareacontainer");
drawCanvas = $("#mycanvasContainer"); // $("#drawAreaContainer")
2013-07-26 22:39:28 +02:00
2014-01-17 16:28:56 +01:00
//console.log("drawCanvasTopLeftCoords: " + drawCanvasTopLeftCoords);
// drawCanvasTopLeftCoords[0] = drawCanvas.css("left").match(/[0-9]/g).join("");
// drawCanvasTopLeftCoords[1] = drawCanvas.css("top").match(/[0-9]/g).join("");
drawCanvasTopLeftCoords[0] = drawCanvas.offset().left;
drawCanvasTopLeftCoords[1] = drawCanvas.offset().top;
// drawCanvasTopLeftCoords[0] = drawCanvas[0].offsetParent.offsetLeft;
// drawCanvasTopLeftCoords[1] = drawCanvas[0].offsetParent.offsetTop;
2013-07-26 22:39:28 +02:00
2014-01-17 16:28:56 +01:00
//console.log("f:initDoodleDrawing() >> canvasWidth: " + canvasWidth);
//console.log("f:initDoodleDrawing() >> canvasHeight: " + canvasHeight);
2013-07-26 22:39:28 +02:00
}
/* * * * * * * * * *
*
* CANVAS DRAWING FUNCTION
*
* * * * * * * * * */
//If _width is not specified, it is calculated from the distance between this and the previous point.
//If _width is negative, the path is 'floating', and only drawn if the setting printer.bottomEnableTraveling is true.
2013-07-26 22:39:28 +02:00
function draw(_x, _y, _width) {
//console.log("canvasDrawing:draw");
//console.log("f:draw() >> _width: " + _width);
2013-07-26 22:39:28 +02:00
if (prevX == 0 && prevY == 0) {
2013-07-26 22:39:28 +02:00
prevX = _x;
prevY = _y;
}
ctx.beginPath();
ctx.moveTo(prevX, prevY);
2016-01-06 20:35:19 +01:00
var lineWeight = null;
if (_width != undefined && _width < 0) {
if (settings['printer.bottomEnableTraveling']) {
ctx.moveTo(_x, _y);
} else {
2016-01-06 20:35:19 +01:00
lineWeight = 0.5;
}
2013-07-26 22:39:28 +02:00
} else {
if (_width != undefined) {
2016-01-06 20:35:19 +01:00
lineWeight = _width;
} else {
if (drawVariableLineWeight) {
var dist = Math.sqrt(Math.pow((prevX - _x), 2) + Math.pow((prevY - _y), 2));
if (dist < 10) {
2016-01-06 20:35:19 +01:00
lineWeight += .25;
} else if (dist < 20) {
2016-01-06 20:35:19 +01:00
lineWeight += .5;
} else if (dist < 30) {
2016-01-06 20:35:19 +01:00
lineWeight += .75;
} else if (dist < 50) {
2016-01-06 20:35:19 +01:00
lineWeight += 1;
} else if (dist < 80) {
2016-01-06 20:35:19 +01:00
lineWeight += 1.5;
} else if (dist < 120) {
2016-01-06 20:35:19 +01:00
lineWeight += 2.25;
} else if (dist < 170) {
2016-01-06 20:35:19 +01:00
lineWeight += 3.5;
} else {
2016-01-06 20:35:19 +01:00
lineWeight += 2;
}
2016-01-06 20:35:19 +01:00
lineWeight = Math.min(lineWeight, 30);
lineWeight *= 0.90;
lineWeight = Math.max(lineWeight, 1.0);
2013-07-26 22:39:28 +02:00
} else {
2016-01-06 20:35:19 +01:00
lineWeight = 2;
2013-07-26 22:39:28 +02:00
}
}
2016-01-06 20:35:19 +01:00
}
2013-07-26 22:39:28 +02:00
2016-01-06 20:35:19 +01:00
if (lineWeight != null) {
ctx.lineCap = 'round';
ctx.lineWidth = lineWeight;
ctx.lineTo(_x, _y);
ctx.stroke();
2013-07-26 22:39:28 +02:00
}
prevX = _x;
prevY = _y;
}
/* * * * * * * * * *
*
* SUPPORTING FUNCTIONS
*
* * * * * * * * * */
function clearDoodle() {
2014-01-17 16:28:56 +01:00
//console.log("f:clearDoodle");
2013-07-26 22:39:28 +02:00
2014-12-17 09:45:40 +01:00
//updatePrevNextButtonStateOnClear();
2013-07-26 22:39:28 +02:00
_points = [];
prevX = 0;
prevY = 0;
updatePrevX = -1;
updatePrevY = -1;
2013-07-26 22:39:28 +02:00
doodleBounds = [-1, -1, -1, -1]; // left, top, right, bottom
doodleTransform = [0, 0, 1.0, 1.0]; // [ x, y, scaleX, scaleY ]
dragging = false;
2013-07-26 22:39:28 +02:00
clearMainView();
resetPreview();
2013-09-18 22:35:38 +02:00
resetVerticalShapes();
setSketchModified(false);
2014-12-17 09:45:40 +01:00
// updateSketchButtonStates();
2013-07-26 22:39:28 +02:00
}
function redrawDoodle(recalcBoundsAndTransforms) {
2014-01-17 16:28:56 +01:00
//console.log("canvasDrawing:redrawDoodle");
if (recalcBoundsAndTransforms == undefined) recalcBoundsAndTransforms = false;
2013-10-29 21:27:17 +01:00
// console.log("f:redrawDoodle() >> recalcBoundsAndTransforms = " + recalcBoundsAndTransforms);
if (recalcBoundsAndTransforms == true) {
doodleBounds = [-1, -1, -1, -1]; // left, top, right, bottom
doodleTransform = [0, 0, 1.0, 1.0]; // [ x, y, scaleX, scaleY ]
for (var i = 0; i < _points.length; i++) {
adjustBounds(_points[i][0], _points[i][1]);
adjustPreviewTransformation();
}
}
clearMainView();
prevX = 0;
prevY = 0;
for (var i = 0; i < _points.length; i++) {
// console.log(" drawing points " + _points[i]);
if (_points[i][2] == true) {
draw(_points[i][0], _points[i][1], -1);
} else {
draw(_points[i][0], _points[i][1]);
}
}
}
2014-01-17 16:28:56 +01:00
// checks if x,y is outside doodleBounds, if so update
2013-07-26 22:39:28 +02:00
function adjustBounds(x, y) {
2014-01-17 16:28:56 +01:00
//console.log("canvasDrawing:adjustBounds");
var newPointsOutsideOfCurrentBounds = false;
// console.log("f:adjustBounds("+x+","+y+")");
2013-07-26 22:39:28 +02:00
if (doodleBounds[0] == -1) {
// if doodleBounds[0] is -1 then it isn't initted yet, so x and y are both the min and max vals
doodleBounds[0] = x;
doodleBounds[1] = y;
doodleBounds[2] = x;
doodleBounds[3] = y;
return;
}
if (x < doodleBounds[0]) {
doodleBounds[0] = x;
newPointsOutsideOfCurrentBounds = true;
}
if (x > doodleBounds[2]) {
doodleBounds[2] = x;
newPointsOutsideOfCurrentBounds = true;
}
if (y < doodleBounds[1]) {
doodleBounds[1] = y;
newPointsOutsideOfCurrentBounds = true;
}
if (y > doodleBounds[3]) {
doodleBounds[3] = y;
newPointsOutsideOfCurrentBounds = true;
}
2013-07-26 22:39:28 +02:00
return newPointsOutsideOfCurrentBounds;
2013-07-26 22:39:28 +02:00
}
// does what exactly?
function adjustPreviewTransformation() {
2014-01-17 16:28:56 +01:00
//console.log("canvasDrawing:adjustPreviewTransformation");
2013-07-26 22:39:28 +02:00
doodleTransform[0] = doodleBounds[0];
doodleTransform[1] = doodleBounds[1];
var sclX, sclY, finalScl;
if (_points.length < 2) {
2013-07-28 02:46:32 +02:00
// console.log(_points);
2013-07-26 22:39:28 +02:00
sclX = 1.0;
sclY = 1.0;
finalScl = Math.min(sclX, sclY);
} else {
sclX = canvasWidth / (doodleBounds[2] - doodleBounds[0]);
sclY = canvasHeight / (doodleBounds[3] - doodleBounds[1]);
// TODO this shouldn't be a matter if choosing the smallest but should probably involve maintaining aspect ratio??
finalScl = Math.min(sclX, sclY);
}
doodleTransform[2] = finalScl;
doodleTransform[3] = finalScl;
}
/* * * * * * * * * *
*
* MOUSE/TOUCH EVENTHANDLERS
*
* * * * * * * * * */
function onCanvasMouseDown(e) {
2014-01-17 16:28:56 +01:00
//console.log("canvasDrawing:onCanvasMouseDown");
setSketchModified(true);
// console.log("f:onCanvasMouseDown()");
// console.log("onCanvasMouseDown >> e.offsetX,e.offsetY = " + e.offsetX+","+e.offsetY);
// console.log("onCanvasMouseDown >> e.layerX,e.layerY= " + e.layerX+","+e.layerY);
// console.log("onCanvasMouseDown >> e: " , e);
2013-07-26 22:39:28 +02:00
dragging = true;
prevCountingTime = new Date().getTime();
movementCounter = 0
2013-07-28 02:46:32 +02:00
var x, y;
if (e.offsetX != undefined) {
x = e.offsetX;
y = e.offsetY;
} else {
x = e.layerX;
y = e.layerY;
}
// console.log(" x: " + x + ", y: " + y);
_points.push([x, y, true]);
adjustBounds(x, y);
2013-07-26 22:39:28 +02:00
adjustPreviewTransformation();
draw(x, y, -1);
2013-07-26 22:39:28 +02:00
}
var prevPoint = {x:-1, y:-1};
2013-07-26 22:39:28 +02:00
function onCanvasMouseMove(e) {
2014-01-17 16:28:56 +01:00
//console.log("canvasDrawing:onCanvasMouseMove");
// console.log("f:onCanvasMouseMove()");
2013-07-26 22:39:28 +02:00
if (!dragging) return;
setSketchModified(true);
2013-07-26 22:39:28 +02:00
// console.log("onmousemove");
2013-07-28 02:46:32 +02:00
var x, y;
if (e.offsetX != undefined) {
x = e.offsetX;
y = e.offsetY;
} else {
x = e.layerX;
y = e.layerY;
}
2016-01-06 20:35:19 +01:00
var prevPresent = prevPoint.x != -1 || prevPoint.y != -1;
var dist = prevPresent ? Math.sqrt(Math.pow((prevPoint.x - x), 2) + Math.pow((prevPoint.y - y), 2)) : undefined;
if (!prevPresent || dist > 5) { // replace dist check by setting: doodle3d.simplify.minDistance
_points.push([x, y, false]);
adjustBounds(x, y);
adjustPreviewTransformation();
draw(x, y);
prevPoint.x = x;
prevPoint.y = y;
2013-07-26 22:39:28 +02:00
}
2016-01-06 20:35:19 +01:00
2013-07-26 22:39:28 +02:00
// DEBUG
// $("#textdump").text("");
// $("#textdump").append("doodlebounds:" + doodleBounds + "\n");
// $("#textdump").append("doodletransform:" + doodleTransform + "\n");
if (new Date().getTime() - prevRedrawTime > redrawInterval) {
// redrawing the whole preview the first X points ensures that the doodleBounds is set well
prevRedrawTime = new Date().getTime();
// Keep fully updating the preview if device is not a smartphone.
// (An assumption is made here that anything greater than a smartphone will have sufficient
// performance to always redraw the preview.)
if (_points.length < 50 || !clientInfo.isSmartphone) {
redrawPreview();
} else {
updatePreview(x, y, true);
}
2013-07-26 22:39:28 +02:00
}
}
prevUpdateFullPreview = 0; // 0 is not a timeframe but refers to the _points array
prevUpdateFullPreviewInterval = 25; // refers to number of points, not a timeframe
2013-07-26 22:39:28 +02:00
function onCanvasMouseUp(e) {
// console.log("f:onCanvasMouseUp()");
2013-07-26 22:39:28 +02:00
// console.log("onmouseup");
dragging = false;
2014-01-17 16:28:56 +01:00
//console.log("doodleBounds: " + doodleBounds);
//console.log("doodleTransform: " + doodleTransform);
2013-07-26 22:39:28 +02:00
// ctx.stroke();
2014-01-17 16:28:56 +01:00
//console.log("_points.length :" + _points.length);
2013-07-26 22:39:28 +02:00
// console.log(_points);
// DEBUG
// $("#textdump").text("");
// $("#textdump").append("doodlebounds:" + doodleBounds + "\n");
// $("#textdump").append("doodletransform:" + doodleTransform + "\n");
// redrawPreview();
renderToImageDataPreview();
2013-07-26 22:39:28 +02:00
}
function onCanvasTouchDown(e) {
setSketchModified(true);
2013-07-26 22:39:28 +02:00
e.preventDefault();
2014-01-17 16:28:56 +01:00
//console.log("f:onCanvasTouchDown >> e: " , e);
2013-07-26 22:39:28 +02:00
// var x = e.touches[0].pageX - e.touches[0].target.offsetLeft;
// var y = e.touches[0].pageY - e.touches[0].target.offsetTop;
var x = e.touches[0].pageX - drawCanvasTopLeftCoords[0];
var y = e.touches[0].pageY - drawCanvasTopLeftCoords[1];
// var x = e.touches[0].pageX;
// var y = e.touches[0].pageY;
// var x = e.touches[0].layerX;
// var y = e.touches[0].layerY;
2013-07-26 22:39:28 +02:00
_points.push([x, y, true]);
adjustBounds(x, y);
adjustPreviewTransformation();
draw(x, y, -1);
2013-07-26 22:39:28 +02:00
movementCounter = 0;
prevRedrawTime = new Date().getTime();
}
function onCanvasTouchMove(e) {
2014-01-17 16:28:56 +01:00
//console.log("canvasDrawing:onCanvasTouchMove");
setSketchModified(true);
2013-07-26 22:39:28 +02:00
e.preventDefault();
// var x = e.touches[0].pageX - e.touches[0].target.offsetLeft;
// var y = e.touches[0].pageY - e.touches[0].target.offsetTop;
var x = e.touches[0].pageX - drawCanvasTopLeftCoords[0];
var y = e.touches[0].pageY - drawCanvasTopLeftCoords[1];
// var x = e.touches[0].layerX;
// var y = e.touches[0].layerY;
// var x = e.touches[0].layerX;
// var y = e.touches[0].layerY;
2013-07-26 22:39:28 +02:00
//console.log("f:onCanvasTouchMove >> x,y = "+x+","+y+" , e: " , e);
2016-01-06 20:35:19 +01:00
var prevPresent = prevPoint.x != -1 || prevPoint.y != -1;
var dist = prevPresent ? Math.sqrt(Math.pow((prevPoint.x - x), 2) + Math.pow((prevPoint.y - y), 2)) : undefined;
if (!prevPresent || dist > 5) { // replace dist check by setting: doodle3d.simplify.minDistance
_points.push([x, y, false]);
2016-01-06 20:35:19 +01:00
adjustBounds(x, y);
adjustPreviewTransformation();
draw(x, y);
prevPoint.x = x;
prevPoint.y = y;
}
2013-07-26 22:39:28 +02:00
// update counter -> this was for getting a handle on how often the Canvas fires a move-event
/*
movementCounter++;
if (new Date().getTime() - prevCountingTime > 1000) {
// console.log("number of moves in 1sec: " + movementCounter)
prevCountingTime= new Date().getTime();
$("#numtimes").text(movementCounter + " times");
movementCounter = 0;
}
//*/
if (new Date().getTime() - prevRedrawTime > redrawInterval) {
// redrawing the whole preview the first X points ensures that the doodleBounds is set well
if (_points.length < 50) {
redrawPreview();
} else {
updatePreview(x, y, true);
/*
if (_points.length - prevUpdateFullPreview > prevUpdateFullPreviewInterval) {
console.log("f:onTouchMove >> passed prevUpdateFullPreviewInterval, updating full preview");
redrawPreview();
prevUpdateFullPreview = _points.length;
} else {
updatePreview(x, y, true);
}
//*/
}
2013-07-26 22:39:28 +02:00
prevRedrawTime = new Date().getTime();
}
}
function onCanvasTouchEnd(e) {
2014-01-17 16:28:56 +01:00
//console.log("f:onCanvasTouchEnd()");
//console.log("doodleBounds: " + doodleBounds);
//console.log("doodleTransform: " + doodleTransform);
// ctx.stroke();
2014-01-17 16:28:56 +01:00
//console.log("_points.length :" + _points.length);
// redrawPreview();
renderToImageDataPreview();
2013-07-26 22:39:28 +02:00
}
function prevent(e) {
e.preventDefault();
}