Is it possible to get strokes from a canvas with Javascript? - javascript

I'm using this drawing app: http://intridea.github.io/sketch.js/
I'm trying to get the stroke 'content' with: var ctx = colors_sketch.getContext("2d");
I'm looking for something that enables me to capture and redraw the canvas context. Like this:
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.moveTo(20,20);
// ... lots of lineTo's etc ...
ctx.lineTo(70,100);
ctx.strokeStyle="red";
ctx.stroke();

You can create a custom wrapper, and call its api to store the drawing operations in array, and when you done, use its api to stroke on canvas.
The wrapper would become mor complex than the snippet if you also intend to wrap other drawing operations like arcTo, bezierCurveTo, rect ... etc. But idea remains the same: Save the operations to a store with specific format, then when you're about to draw them on canvas, use ctx operations to replay those operations.
var StokeStore = function() {
this.store = [];
this.current = [];
}
StokeStore.prototype.moveTo = function(x, y) {
if (this.current.length !== 0) {
this.store.push(this.current);
this.current = [];
}
this.current.push({x: x, y: y});
};
StokeStore.prototype.lineTo = function(x, y) {
this.current.push({x: x, y: y});
};
StokeStore.prototype.stroke = function(ctx, style) {
ctx.beginPath();
ctx.strokeStyle = style ? style : 'black';
this.store.forEach(function(line) {
this._stroke(line);
}, this);
this._stroke(this.current);
ctx.stroke();
};
StokeStore.prototype._stroke = function(line) {
var length = line.length;
if (length < 2) {
return;
}
ctx.moveTo(line[0].x, line[0].y);
var index, pt;
for (index = 1; index < length; ++index) {
pt = line[index];
ctx.lineTo(pt.x, pt.y);
}
};
var canvas = document.getElementById('test');
var ctx = canvas.getContext('2d');
var print = document.getElementById('print');
var clear = document.getElementById('clear');
var exampleStroke = new StokeStore();
exampleStroke.moveTo(50, 50);
exampleStroke.lineTo(70, 70);
exampleStroke.lineTo(200, 50);
exampleStroke.lineTo(200, 190);
exampleStroke.moveTo(30, 90);
exampleStroke.lineTo(0, 290);
exampleStroke.lineTo(290, 40);
exampleStroke.lineTo(150, 150);
var randomColor = ['red', 'cyan', 'black', 'purple'];
print.addEventListener('click', function() {
var rnd = Math.floor(Math.random() * randomColor.length);
var style = randomColor[rnd];
exampleStroke.stroke(ctx, style);
});
clear.addEventListener('click', function() {
canvas.width = canvas.width;
});
<canvas id="test" width="300" height="300"></canvas>
<button id="print">print</button>
<button id="clear">clear</button>
Update to markE's comment:
I'm not good at modifying jQuery plugins, but it seems sketch.js do provide a storage itself, when you call its api, it sets data-sketch attribute to store its created instance, so you can try to interact with that instance, like its redraw or else.
Also, it use a similar format to store the sketch history, if we use var sketch = $(CANVAS).data('sketch') to get the instance, we can use sketch.actions to get all stroke, and each stroke has an array called events, which stores Objects with attribute x, y, eventType, so if you want, you can either retrieve the strokes from it, or put your own stroke into the history. Like:
sketch.actions.push({
color: //stroke color,
size: // stroke size,
tool: // marker will draw, while eraser will erase to white,
events: [
{x:xval, y:yval, event:evType},....
]
});
jsfiddle or snippet below.
$(function() {
var $cv = $('#test');
var cv = $cv.get(0);
$('#test').sketch();
var sketch = $cv.data('sketch');
$('#clear').click(function() {
cv.width = cv.width;
});
$('#redraw').click(function() {
sketch.redraw();
});
$('#strokes').click(function() {
var $display = $('#display').empty();
sketch.actions.forEach(function(strk, idx) {
if (!strk.events) {
return;
}
var $div = $('<div>').addClass('stroke');
$('<div>').text('Stroke #' + idx).appendTo($div);
strk.events.forEach(function(pt, idx) {
$("<p>").text(idx + ': (' + pt.x + ',' + pt.y + ')' ).appendTo($div);
});
$div.appendTo($display);
});
});
});
#test {
border: solid 1px gray;
}
.stroke {
border: solid 1px blue;
float : left;
padding: 10px;
margin: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/intridea/sketch.js/master/lib/sketch.min.js"></script>
<canvas id="test" width="500" height="500;"></canvas>
<button id="clear">clear</button>
<button id="redraw">redraw</button>
<button id="strokes">print strokes</button>
<div id="display"></div>

Related

Setting background image and work on top of it

I am using the below HTML to draw paths using paper.js. On the background we want to set a background image.
I tried to set image 'room.jpeg' which is stored locally. It loads correctly but it is not in the background. As a result it gets removed when I try drawing the path. The image should fit in the browser window.
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.14/fabric.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.15/paper-full.js"></script>
<script type="text/paperscript" canvas="canvas">
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var img1 = new Image();
//drawing of the test image - img1
img1.onload = function() {
//draw background image
ctx.drawImage(img1, 0, 0);
//draw a box over the top
ctx.fillStyle = "rgba(200, 0, 0, 0.5)";
ctx.fillRect(0, 0, 500, 500);
};
img1.src = 'https://i.imgur.com/6gU9m8O.png'; // 'room.jpeg'; amended for this demo
var path;
var currentPath = [];
var textItem = new PointText({
content: '',
point: new Point(20, 30),
fillColor: 'black',
});
function onMouseDown(event) {
// If we produced a path before, deselect it:
if (path) {
path.selected = false;
}
// Create a new path and set its stroke color to black:
path = new Path({
segments: [event.point],
strokeColor: 'black',
// Select the path, so we can see its segment points:
fullySelected: false
});
}
// While the user drags the mouse, points are added to the path
// at the position of the mouse:
function onMouseDrag(event) {
console.log('Capturing new path');
path.add(event.point);
var point = event.point;
currentPath.push(point.x + ', ' + point.y);
// Update the content of the text item to show how many
// segments it has:
textItem.content = '';
}
// When the mouse is released, we simplify the path:
function onMouseUp(event) {
var segmentCount = path.segments.length;
// console.log(currentPath.toString());
console.log('End');
var poi = prompt("Please enter your poi start and end");
console.log('Saving Paths' + poi + (currentPath.toString()));
// When the mouse is released, simplify it:
path.simplify(10);
// Select the path, so we can see its segments:
path.fullySelected = false;
var newSegmentCount = path.segments.length;
var difference = segmentCount - newSegmentCount;
var percentage = 100 - Math.round(newSegmentCount / segmentCount * 100);
textItem.content = '';
}
</script>
<canvas id="canvas" resize></canvas>
Using an img as background gives more trouble since you'll need to redraw/move it on every run.
I'd just use some css to set an background-image to the <canvas> itself:
canvas {
width: 100vw;
height: 100vh;
background-image: url('https://via.placeholder.com/500/FFFFF3?text=BG');
}
canvas {
width: 100vw;
height: 100vh;
background-image: url('https://via.placeholder.com/500/FFFFF3?text=BG');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.15/paper-full.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.15/paper-core.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.14/fabric.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" resize></canvas>
<script type="text/paperscript" canvas="canvas">
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var path;
var currentPath = [];
var textItem = new PointText({
content: '',
point: new Point(20, 30),
fillColor: 'black',
});
function onMouseDown(event) {
// If we produced a path before, deselect it:
if (path) {
path.selected = false;
}
// Create a new path and set its stroke color to black:
path = new Path({
segments: [event.point],
strokeColor: 'black',
// Select the path, so we can see its segment points:
fullySelected: false
});
}
// While the user drags the mouse, points are added to the path
// at the position of the mouse:
function onMouseDrag(event) {
//console.log('Capturing new path');
path.add(event.point);
var point = event.point;
currentPath.push(point.x + ', ' + point.y);
// Update the content of the text item to show how many
// segments it has:
textItem.content = '';
}
// When the mouse is released, we simplify the path:
function onMouseUp(event) {
var segmentCount = path.segments.length;
// console.log(currentPath.toString());
// console.log('End');
var poi = prompt("Please enter your poi start and end");
console.log('Saving Paths' + poi + (currentPath.toString()));
// When the mouse is released, simplify it:
path.simplify(10);
// Select the path, so we can see its segments:
path.fullySelected = false;
var newSegmentCount = path.segments.length;
var difference = segmentCount - newSegmentCount;
var percentage = 100 - Math.round(newSegmentCount / segmentCount * 100);
textItem.content = '';
}
</script>

Canvas text rendering

I can really use some help, my goal is to add few lines to the canvas in different places, it means to use the function drawText few times, for some reason if I don't use drawText inside the onload of drawImage the text does not rendering I am really stuck and can use some help, my main target it to make website that can edit pictures and make memes (e.g.: https://imgflip.com/memegenerator)and adding text line is what i am getting stuck on because I don't understand how to render new text line while save the old one, every time i start new line its like the image rendering all over again and start from the beginning.
// Function to load image on the canvas
function drawImg(url) {
gCurrLineIdx = getCurrLineIdx();
let currLine = gMeme.lines[gCurrLineIdx];
const img = new Image();
img.src = url;
img.onload = () => {
gCtx.drawImage(img, 0, 0, gElCanvas.width, gElCanvas.height);
//If you dont call drawText the text does not render to the canvas
drawText(currLine.txt, currLine.size, currLine.fontColor, currLine.strokeColor, currLine.align, currLine.font, gElCanvas.width / 2, currLine.y);
};
}
// Function to add text on the canvas
function drawText(text = '', fontSize = 20, fontColor = 'white', strokeColor = 'black', align = 'center', font = "ariel", x = gElCanvas.width / 2, y = 20) {
gCtx.strokeStyle = strokeColor;
gCtx.fillStyle = fontColor;
gCtx.font = `${fontSize}px ${font}`;
gCtx.textAlign = align;
gCtx.fillText(text, x, y);
gCtx.strokeText(text, x, y);
}
//Function to add new text line on the canvas.
function onAddTextLine() {
let textInput = document.getElementById('text-input');
textInput.value = '';
addTextLine();
gCurrLineIdx = getCurrLineIdx();
var currLine = gMeme.lines[gCurrLineIdx];
drawText(currLine.txt, currLine.size, currLine.fontColor, currLine.strokeColor, currLine.align, currLine.font, gElCanvas.width / 2, currLine.y);
}
The question I see here is:
how to render new text line while save the old one
Looks like in your code you are drawing things independently, below is a different approach the class Meme has a few functions to add text and image but every time anything change the entire canvas is cleared (clearRect) and every element is re-drawn, the magic is in the this.draw(), that is the call to the common function that does all the drawing.
To keep my sample small I hard-coded many of the things you had as parameters, it should be easy for you to reintroduce them if you need
class Meme {
constructor(ctx, width, height) {
this.ctx = ctx;
this.ctx.font = '80px Arial';
this.ctx.fillStyle = "blue"
this.ctx.textAlign = "center"
this.width = width;
this.height = height;
}
addHeadText(text) {
this.htext = text;
this.draw();
}
addFootText(text) {
this.ftext = text;
this.draw();
}
addImage(image_src) {
this.image = new Image();
this.image.src = image_src;
this.image.onload = () => {
this.draw()
};
}
draw() {
this.ctx.beginPath();
this.ctx.clearRect(0, 0, this.width, this.height)
if (this.image) {
this.ctx.drawImage(this.image, 0, 0, this.width, this.height);
}
if (this.htext) {
this.ctx.textBaseline = "top";
this.ctx.fillText(this.htext, this.width / 2, 0);
}
if (this.ftext) {
this.ctx.textBaseline = "bottom";
this.ctx.fillText(this.ftext, this.width / 2, this.height);
}
this.ctx.closePath();
}
}
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
meme = new Meme(ctx, canvas.width, canvas.height)
meme.addHeadText("Hello");
meme.addFootText("World");
meme.addImage("http://i.stack.imgur.com/UFBxY.png");
document.getElementById('htext').onkeyup = (event) => {
meme.addHeadText(event.srcElement.value);
};
document.getElementById('ftext').onkeyup = (event) => {
meme.addFootText(event.srcElement.value);
};
Head Text:<input type="text" id="htext" name="ftext" style="width: 140px;" value="Hello"><br>
Foot Text:<input type="text" id="ftext" name="ftext" style="width: 140px;" value="World"><br>
<canvas id="c" width=280 height=380 style="border:2px solid red;"></canvas>

How to store and restore canvas to use it again?

I am using PDF.js to show PDF in browser. PDF.js uses canvas to render PDF. I have js scripts that draws the lines on the canvas when user double clicks on the canvas. It also adds X check mark to remove the already drawn line.
based on my research i cannot simply just remove the line from the canvas because underneath pixels are gone when you draw something on it. To get it working i have to store lines and then clear canvas and re-load canvas and re-draw lines
Issue
I am not able to store canvas and restore canvas. When i click on X i was able to get lines re-drawn but canvas does not get restored. Canvas remains blank
Run the demo in full page
$(function () {
var $canvas = $("#myCanvas");
var canvasEl = $canvas.get(0);
var ctx = canvasEl.getContext("2d");
var lines = [];
var backupCanvas = document.createElement("canvas");
var loadingTask = pdfjsLib.getDocument('https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf');
loadingTask.promise.then(function (doc) {
console.log("This file has " + doc._pdfInfo.numPages + " pages");
doc.getPage(1).then(page => {
var scale = 1;
var viewPort = page.getViewport(scale);
canvasEl.width = viewPort.width;
canvasEl.height = viewPort.height;
canvasEl.style.width = "100%";
canvasEl.style.height = "100%";
var wrapper = document.getElementById("wrapperDiv");
wrapper.style.width = Math.floor(viewPort.width / scale) + 'px';
wrapper.style.height = Math.floor(viewPort.height / scale) + 'px';
page.render({
canvasContext: ctx,
viewport: viewPort
});
storeCanvas();
});
});
function storeCanvas() {
backupCanvas.width = canvasEl.width;
backupCanvas.height = canvasEl.height;
backupCanvas.ctx = backupCanvas.getContext("2d");
backupCanvas.ctx.drawImage(canvasEl, 0, 0);
}
function restoreCanvas() {
ctx.drawImage(backupCanvas, 0, 0);
}
$canvas.dblclick(function (e) {
var mousePos = getMousePos(canvasEl, e);
var line = { startX: 0, startY: mousePos.Y, endX: canvasEl.width, endY: mousePos.Y, pageY: e.pageY };
lines.push(line);
drawLine(line, lines.length - 1);
});
function drawLine(line, index) {
// draw line
ctx.beginPath();
ctx.strokeStyle = '#df4b26';
ctx.moveTo(line.startX, line.startY);
ctx.lineTo(line.endX, line.endY);
ctx.closePath();
ctx.stroke();
// add remove mark
var top = line.pageY;
var left = canvasEl.width + 20;
var $a = $("<a href='#' class='w-remove-line'>")
.data("line-index", index)
.attr("style", "line-height:0")
.css({ top: top, left: left, position: 'absolute' })
.html("x")
.click(function () {
var index = $(this).data("line-index");
$(".w-remove-line").remove();
ctx.clearRect(0, 0, canvasEl.width, canvasEl.height);
// restore canvas
restoreCanvas();
lines.splice(index, 1);
for (var i = 0; i < lines.length; i++) {
drawLine(lines[i], i);
}
});
$("body").append($a);
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
X: Math.floor(evt.clientX - rect.left),
Y: Math.floor(evt.clientY - rect.top),
};
}
});
canvas {
border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.2.228/pdf.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<b> Double Click on PDF to draw line and then click on X to remove lines</b>
<div id="wrapperDiv">
<canvas id="myCanvas"></canvas>
</div>
The PDF.js render() function is async so you need to store the canvas after the render has finished. Your code is firing storeCanvas() too early and storing a blank canvas. Easy fix, render() returns a promise so ...
page.render({
canvasContext: ctx,
viewport: viewPort
}).then( () => {
storeCanvas();
});
https://jsfiddle.net/fyLant01/1/
Reference: from https://github.com/mozilla/pdf.js/blob/master/src/display/api.js#L998
/**
* Begins the process of rendering a page to the desired context.
* #param {RenderParameters} params Page render parameters.
* #return {RenderTask} An object that contains the promise, which
* is resolved when the page finishes rendering.
*/

Binding Canvas images to events based on class

I have the following fiddle here: http://jsfiddle.net/tbt0jspd/2/
The idea is to display a series of boxes on the screen using the box image that will have a class of box on them but ONE will have a class of win and the rest will have a class of lose.
This is how I handle adding the boxes to the canvas element:
var boxes = 6;
var boxImg = new Image();
boxImg.src = 'img/box.png';
boxImg.onload = function() {
for (var i = 0, x = 20, y = 200; i < boxes; x += 148, y = 200, i++) {
context.drawImage(boxImg, x, y);
}
};
The first question is how do I add the classes as described above to the images? They should all have a class of box, and 5 should have a class of lose, and 1 a class of win.
Users will then click these boxes and a class of opened will be applied to them in turn. The boxes will change to a different image depending on their class of win or lose.
$('.box').not('.opened').on('click', function() {
if( $(this).hasClass('win') ) {
$(this).src = 'img/box-win.png';
} else if( $(this).hasClass('lose') ) {
$(this).src = 'img/box-lose.png';
}
$(this).addClass('opened');
if( $('.opened').length == boxes )
{
alert('all boxes open');
}
});
You can't have classes on boxes that or on canvas, because after you draw an image on canvas, it becomes nothing more but a set of pixels.
What you can do, however, is modify which image gets drawn on the canvas based on its class (or another property), but you'll have to redraw it on the canvas whenever it's changed.
Redrawing them on canvas is the key.
For easier control, you might consider using an object to represent boxes (not just their images), so you can easily toggle their states/images/etc.
UPDATE
Here is a simple example using the button to open all the boxes and assign them win/lose state randomly: http://jsfiddle.net/d7ov9pak/
var boxes = 6;
var canvas = document.getElementById('OpenTheBox');
var context = canvas.getContext('2d');
var boxImg = new Image();
boxImg.src = 'http://i59.tinypic.com/vqp4c7.png';
var winImg = new Image();
winImg.src = 'http://i60.tinypic.com/2ujtr0i.png';
var loseImg = new Image();
loseImg.src = 'http://i60.tinypic.com/oivsc0.png';
var cwidth = canvas.width = window.screen.width;
var cheight = canvas.height = window.screen.height;
var ctop = canvas.offsetTop;
var cleft = canvas.offsetLeft;
context.fillStyle = '#000000';
context.fillRect(0, 0, cwidth, cheight);
canvas.oncontextmenu = function (e) {
e.preventDefault();
};
boxImg.onload = function () {
for (var i = 0, x = 20, y = 200; i < boxes; x += 148, y = 200, i++) {
context.drawImage(boxImg, x, y);
}
};
function openBoxes() {
// clear the canvas, just in case
canvas.width = canvas.width;
for (var i = 0, x = 20, y = 200; i < boxes; x += 148, y = 200, i++) {
// assign a random win/lose box
var image = (Math.random() >= 0.5) ? winImg : loseImg;
context.drawImage(image, x, y);
}
}
* {
margin: 0;
padding: 0;
border: 0;
outline: 0;
}
html, body {
width: 100%;
height: 100%;
overflow: hidden;
background: #000000;
}
<button onclick="openBoxes()">Open the boxes</button>
<canvas id="OpenTheBox"></canvas>
Note, if this is all there is to it and you don't need any other canvas functionality, perhaps you should consider not using the canvas, and simply manipulate DOM element to show different images based on CSS classes.

HTML5 Canvas flicker in FireFox 4

I'm working on a proof of concept on an HTML5 canvas. I was able to get this working like a charm in Chrome and IE9, but in Firefox 4 I'm getting constant flicker as it redraws the canvas. I've tried a few techniques mentioned on this site like double buffering but I'm still getting a large amount of flicker. Any insight on this would be appreciated!
<!DOCTYPE HTML>
<html>
<head>
<style type="text/css">
body
{
margin:0px;
padding:0px;
text-align:center;
}
canvas
{
outline:0;
border:1px solid #000;
margin-top: 10px;
margin-left: auto;
margin-right: auto;
}
</style>
<script type="text/javascript">
var canvasWidth = 640;
var thisXPos = 0;
var canvasHeight = 820;
var thisYPos = 0;
var canvas = null;
var context = null;
var gLoop = null;
var rain = [];
var rainImg = "images/raindrop.gif";
var bgImg = null;
var i;
for (i = 0; i < howManyLetters; i++)
{
rain.push([Math.floor(Math.random() * canvasWidth), Math.floor(Math.random() * canvasHeight),rainImg]);
}
var DrawRain = function()
{
for (i = 0; i < 10; i++)
{
thisXPos = rain[i][0];
thisYPos = rain[i][1];
imgSrc = rain[i][2];
letterImg = new Image();
letterImg.setAtX = thisXPos;
letterImg.setAtY = thisYPos;
letterImg.onload = function()
{
context.drawImage(this, this.setAtX, this.setAtY);
}
letterImg.src = imgSrc;
}
};
var MoveRain = function(e)
{
for (i = 0; i < 10; i++)
{
if ((rain[i][1] - 5) > canvasHeight)
{
randomnumber = Math.floor(Math.random()*26);
rain[i][0] = Math.random() * canvasWidth;
rain[i][1] = 0;
rain[i][2] = rainImg;
}
else
{
rain[i][1] += e;
}
}
};
var clear = function()
{
context.beginPath();
context.rect(0, 0, canvasWidth, canvasHeight);
context.closePath();
bgImg = new Image();
bgImg.src = "images/bg.png";
bgImg.onload = function()
{
context.drawImage(bgImg,0,0);
}
}
var GameLoop = function()
{
context.save();
clear();
MoveRain(1);
DrawRain();
context.restore();
gLoop = setTimeout(GameLoop, 10);
}
function loadGame()
{
canvas = document.getElementById("gameCanvas");
context = canvas.getContext("2d");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
GameLoop();
}
</script>
</head>
<body onload="loadGame();">
<canvas id="gameCanvas"></canvas>
</body>
</html>
I have distilled your example down to this:
http://jsfiddle.net/sPm3b/6/
And it works very fast in Firefox and Chrome.
So we know that the problem lies in the images.
You need to optimize how they are created and loaded. Right now, each clear() creates a new image and waits for it to load! That image should be created only once, in your loadGame() and then reused over and over.
Same exact deal with letterImg in DrawRain(). Move the creation of it to loadGame()
That will probably fix the problem.
EDIT:
like this:
At the top add:
var letterImg = new Image();
var bgImg = new Image();
Then
function loadGame()
{
canvas = document.getElementById("gameCanvas");
context = canvas.getContext("2d");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
bgImg.src = "images/bg.png";
letterImg.src = "images/raindrop.gif";
// optional: wait for them to load here
GameLoop();
}
Then drawRain, for example, would look like this:
var DrawRain = function()
{
for (i = 0; i < 10; i++)
{
thisXPos = rain[i][0];
thisYPos = rain[i][1];
context.drawImage(letterImg, thisXPosX, thisYPos); // letterImg was already constructed, no need to make it again
}
};
In complement to Simon Sarris response. I've used a 'double canvas' technique to avoid screen fickering with heavy canvas.
The way it works is always have 2 version of the canvas, one in DOM, one outside, and always draw on the one which is not in DOM. I use it with a redraw queue.
here's a part of a working code
(...)
clear: function() {
//rotating on 2 canvas, one for draw (outside DOM) one for show
var self = this;
if (null == self.canvasbackup) {
var tmpcanvas = self.canvas.clone(true);
self.canvasbackup = self.canvas;
self.canvas=tmpcanvas;
} else {
var tmpcanvas = self.canvasbackup;
self.canvasbackup = self.canvas;
self.canvas=tmpcanvas;
}
self.ctx = self.canvas[0].getContext('2d');
self.ctx.clearRect( 0, 0, self.options.width, self.options.height );
jQuery.each(self.elements,function(idx,elt){
// custom function: my elements need to know which canvas they depends on
elt.reconnectCanvas(self.canvas,self.ctx);
});
},
inDOM: function() {
var self = this;
if(null==self.canvasbackup) {
//1st time need to get all things in DOM
self.canvas.appendTo(self.div);
self.div.appendTo(self.container);
} else {
// remove current shown canvas
self.connectHuman();
self.canvasbackup.remove();
// loosing some events here...
self.canvas.appendTo(self.div);
// div is already in DOM, we are in redraw
}
},
redraw: function() {
var self = this;
self.clear();
jQuery.each(self.elements,function(idx,elt){
elt.draw();
elt.enddraw();
});
self.inDOM();
}
(...)

Categories

Resources