Performance decrease when adding KineticJS nodes to canvas - javascript

I'm working on a floorplan editor program which is implemented in part using HTML5 Canvas and KineticJS. The user can select from a couple of tools to place nodes on the canvas (rooms, hallways, staircases, etc), and can then create edges between the nodes to link them.
I'm running into a problem when placing a specific type of node on my canvas: I can add any number of most types of nodes I've got defined without any performance decrease, but as soon as I try and add more than a handful of 'room' nodes, they take longer and longer to render and the stage tap event handler which creates nodes becomes unresponsive. This issue only occurs on the iPad and not when I run the application from a desktop.
All nodes are comprised of a Kinetic Circle with a particular image to represent the type of node and some data such as x/y position, type, id, and a list of attached edges. The only difference between room nodes and other special nodes is an extra Kinetic Rect and a couple of variables to represent the room itself. When creating a new node, all the attributes are filled by the constructor function, then the node is passed to a setup function to register event handlers and a render function to render it based on its type.
I'm still fairly new with these technologies, so any advice, no matter how specific or general, will probably be helpful. I've attached what I think will be helpful snippets of code; if you need to see more or have questions about what's here please let me know.
Thank you so much for any time and effort.
=========================================================================
EDIT:
Removing the opacity attribute of the room nodes made a huge difference; the performance decrease is almost entirely negligible now. I'll post further updates if and when I work out why that's the case.
function Node(x, y, id, type, attr) {
this.x = x;
this.y = y;
this.nX = 0;
this.nY = 0;
this.type = type;
this.bbox;
this.id = id;
this.edges = {};
this.attr = {"zPos": 0,
"name": '',
"width": default_room_width,
"height": default_room_height};
this.render(x, y, node_radius);
}
Node.prototype.render = function(x, y, r){
//Create node on canvas
this.visual = null;
var _self = this;
if(this.type == "node" || this.type == "Hallway"){
this.visual = new Kinetic.Circle({
x: x,
y: y,
radius: r,
fill: '#2B64FF',
stroke: '#000000',
strokeWidth: 2,
draggable: true
});
nodeLayer.add(this.visual);
this.x = this.visual.x();
this.y = this.visual.y();
nodeLayer.draw();
this.visual.id = this.id;
this.setupNode(x, y, node_radius);
} else {
var image = new Image();
_self.visual = new Kinetic.Image({
x: x - (node_img_size / 2),
y: y - (node_img_size / 2),
image: image,
width: node_img_size,
height: node_img_size,
draggable: true
});
image.onload = function(){
_self.setupNode(x, y, node_radius);
nodeLayer.add(_self.visual);
_self.x = _self.visual.x();
_self.y = _self.visual.y();
nodeLayer.draw();
_self.visual.id = _self.id;
}
image.src = '../../img/' + this.type + 'tool.png';
var width = this.attr["width"];
var height = this.attr["height"];
if(this.type== "room") {
this.bbox = new Kinetic.Rect({
x: x,
y: y,
strokeWidth: 2,
stroke: "black",
fill: "black",
opacity: 0.5,
listening: true,
width: width,
height: height,
offset: {x:width/2, y:height/2}
});
setupRoom(this.bbox);
this.bbox.offsetX(default_room_width/2);
this.bbox.offsetY(default_room_height/2);
roomLayer.add(this.bbox);
roomLayer.draw();
}
}
}
//Bind event handlers for rooms
function setupRoom(room) {
room.on(tap, function(e) {
if(selectedRoom == this) {
selectedRoom = null;
this.setOpacity(0.5);
roomLayer.draw();
} else {
if(selectedRoom != null)
selectedRoom.setOpacity(0.5);
selectedRoom = this;
this.setOpacity(1);
roomLayer.draw();
}
});
room.on('mouseenter', function(e) {
is_hovering = true;
}).on('mouseleave', function(e) {
is_hovering = false;
});
}
Node.prototype.setupNode = function (x, y) {
var _self = this;
var c = this.visual;
c.on('mouseenter', function(e){
is_hovering = true;
}).on('mouseleave', function(e){
is_hovering = false;
});
c.on(tap, function(e){
if(is_adding_node == true && _self.type == "node" && linkerNode != _self) {
is_adding_node = false;
nodeDrag = false;
$.each(nodes, function(key, value) {
if(value.type == "node") {
value.visual.fill("#2B64FF");
}
});
nodeLayer.batchDraw();
joinNodes(linkerNode, _self);
} else {
handleNodeTap(e, _self);
}
});
c.on(dbltap, function(e){
console.log(_self.id);
if(selectedTool != "link"){
showMenuForNode(c);
}
});
//Drag event
c.on(touchstart, function(e){
nodeDrag = true;
}).on(touchmove, function(e){
var touchPos = stage.getPointerPosition();
var newX = c.x() + offsetX * -1;
var newY = c.y() + offsetY * -1;
_self.x = newX;
_self.y = newY;
if(_self.text != null) {
_self.text.x(_self.visual.x() - node_text_offset);
_self.text.y(_self.visual.y() - node_text_offset);
}
//Move room BB if set
if (_self.bbox != undefined) {
_self.bbox.x(_self.visual.x() + _self.visual.width()/2);
_self.bbox.y(_self.visual.y() + _self.visual.height()/2);
roomLayer.batchDraw();
}
//Update positions of connected edges
for(var x in _self.edges){
edges[_self.edges[x]].setPosition();
}
nodeLayer.batchDraw();
}).on(touchend, function(e){
currentNode = _self;
nodeDrag = false;
});
};

Related

PIXI JS Priority call mouseover event

When we create multiple sprites, the function mouseover is called when any hover in hitArea polygon. Regardless, whether applied to another object.
Visibility of sprite governed by sorting the array. The later was added to the sprite in stage.children, the higher it will be. Here is an example in which one rectangle superimposed on the other. At the same time, when we put things on the upper left corner of the bottom sprite, at the top of the object function mouseover will work call, although it is under the other.
How to solve this problem? hitarea not suitable, since the facilities will be constantly dragging.
Thanks in advance for your reply!
var stage = new PIXI.Stage(0x97c56e, true);
var renderer = PIXI.autoDetectRenderer(window.innerWidth, window.innerHeight, null);
document.body.appendChild(renderer.view);
renderer.view.style.position = "absolute";
renderer.view.style.top = "0px";
renderer.view.style.left = "0px";
requestAnimFrame( animate );
var texture = new PIXI.RenderTexture()
r1 = new PIXI.Graphics()
r1.beginFill(0xFFFF00);
r1.drawRect(0, 0, 400, 400)
r1.endFill()
texture.render(r1);
var texture2 = new PIXI.RenderTexture()
r1 = new PIXI.Graphics()
r1.beginFill(0xDDDD00);
r1.drawRect(0, 0, 300, 300)
r1.endFill()
texture2.render(r1);
createBunny(100, 100, texture)
createBunny(120, 120, texture2)
function createBunny(x, y, texture) {
var bunny = new PIXI.Sprite(texture);
bunny.interactive = true;
bunny.buttonMode = true;
bunny.anchor.x = 0.5;
bunny.anchor.y = 0.5;
bunny.scale.x = bunny.scale.y = 0.5;
bunny.mouseover = function(data) {
console.log('mouse over!')
}
bunny.mousedown = bunny.touchstart = function(data) {
this.data = data;
this.alpha = 0.9;
this.dragging = true;
this.sx = this.data.getLocalPosition(bunny).x * bunny.scale.x;
this.sy = this.data.getLocalPosition(bunny).y * bunny.scale.y;
};
bunny.mouseup = bunny.mouseupoutside = bunny.touchend = bunny.touchendoutside = function(data) {
this.alpha = 1
this.dragging = false;
this.data = null;
};
bunny.mousemove = bunny.touchmove = function(data) {
if(this.dragging) {
var newPosition = this.data.getLocalPosition(this.parent);
this.position.x = newPosition.x - this.sx;
this.position.y = newPosition.y - this.sy;
}
}
bunny.position.x = x;
bunny.position.y = y;
stage.addChild(bunny);
}
function animate() {
requestAnimFrame( animate );
renderer.render(stage);
}
http://jsfiddle.net/sD8Tt/48/
I know this is old thread, but for those who come to this page, the issue can be fixed by extending the PIXI's Sprite Class, Look at the following code.
PIXI.Sprite.prototype.bringToFront = function() {
if (this.parent) {
var parent = this.parent;
parent.removeChild(this);
parent.addChild(this);
}
}
And call above method in mousedown event like this
this.bringToFront();
Working JSFiddle
http://jsfiddle.net/6rk58cqa/

reload canvas createjs/easeljs animation with ajax load causes layering or display issue

I have a canvas animation that has been created with createjs. The entire animation script including init() function is loaded via jquery: $.getScript() on page load.
The init() and handlecomplete() function included below is then run which attaches the animation to a html canvas element on the page.
var canvas, stage, exportRoot, audio;
var tweens = [];
function init() {
canvas = document.getElementById("canvas");
images = images||{};
if (stage) {
stage.enableDOMEvents(false);
stage.removeAllChildren();
createjs.Ticker.removeAllEventListeners()
stage.enableDOMEvents(true);
}
if (audio ) {
audio.stop();
}
removeTweens();
exportRoot = null;
audio = null;
stage = null;
var loader = new createjs.LoadQueue(false);
loader.installPlugin(createjs.Sound);
loader.addEventListener("fileload", handleFileLoad);
loader.addEventListener("complete", handleComplete);
loader.loadManifest(lib.properties.manifest);
}
function handleComplete() {
exportRoot = new lib.animation2();
stage = new createjs.Stage(canvas);
stage.addChild(exportRoot);
stage.update();
stage.canvas.width = 1280;
stage.canvas.height = 720;
resizeToFit();
stage.update();
createjs.Ticker.setFPS(lib.properties.fps);
createjs.Ticker.addEventListener("tick", stage);
createjs.Ticker.addEventListener("tick", updateTimer);
if (lib.properties.audiovolume) {
audio = createjs.Sound.play("audio", createjs.Sound.INTERRUPT_EARLY, 0, 0, -1, lib.properties.audiovolume);
}
exportRoot.gotoAndPlay(startFrame );
}
My issue is when the user makes a change, we load the script a second time using the same jquery method which returns the updated script. The init() function then executes properly and the new animation plays correctly, but our animated text (using the animateText below) does not appear on the canvas. This function is also loaded dynamically with other functions.
Checking the tween arrays, they are being created and removed as required, but they are not visible.
They are either layered behind the new animation, or not being attached to the new canvas or something else?
Simply refreshing the page will then load the new script and text properly. So clearly something in the dynamic loading of the script?
var animateText = function(localString, startX, startY, letterClip, endObject, font, color) {
var waitAmount = 0;
var offSetAmount = 20;
for(var i = 0; i < localString.length; i++){
var fl_MyInstance = new letterClip();
fl_MyInstance.localName.text = localString[i];
if(font != null){
fl_MyInstance.localName.font = font;
}
if(color != null){
fl_MyInstance.localName.color = color;
}
var localX = startX;
var localY = startY;
fl_MyInstance.x = startX + offSetAmount;
var beginX = startX + offSetAmount
offSetAmount = offSetAmount - 4
fl_MyInstance.y = startY;
fl_MyInstance.alpha = 0;
fl_MyInstance.scaleX = 0.1;
fl_MyInstance.scaleY = 0.1;
var bounds = fl_MyInstance.getBounds();
startX += bounds.width + 0;
var target = fl_MyInstance;
var tween = createjs.Tween.get(target, {
loop: false
}).wait(waitAmount)
.to({
x: localX,
y: localY,
alpha: 1,
scaleX: 1,
scaleY: 1
}, 400, createjs.Ease.circOut);
tween.waitAmount = waitAmount;
if(endObject == null){
tween.endObject = {
x: localX,
y: localY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}
} else {
tween.endObject = {
x: localX - endObject.x,
y: localY - endObject.y,
alpha: endObject.alpha,
scaleX: endObject.scaleX,
scaleY: endObject.scaleY
}
}
tween.targetClip = fl_MyInstance;
tween.arrayIndex = tweens.length;
tweens.push(tween);
waitAmount += 20;
stage.addChild(fl_MyInstance);
}
}
var removeTweens = function(){
for(var i = 0; i<tweens.length; i++){
if(tweens[i] != null){
var tween = tweens[i];
stage.removeChild(tween.targetClip);
tweens[tween.arrayIndex] = null;
}
}
}
var closeTweens = function(){
for(var i = 0; i<tweens.length; i++){
if(tweens[i] != null){
var tween = tweens[i];
createjs.Tween.get(tween.targetClip, {
loop: false
}).wait(tween.waitAmount).to(tween.endObject, 400, createjs.Ease.circOut).call(function(){
stage.removeChild(tween.targetClip);
tweens[tween.arrayIndex] = null;
});
}
}
}
var finalTweens = function(){
for(var i = 0; i<tweens.length; i++){
if(tweens[i] != null){
var tween = tweens[i];
createjs.Tween.get(tween.targetClip, {
loop: false
}).to(tween.endObject, 400, createjs.Ease.circOut);
}
}
}
Since the rest of the animation works perfectly using this method of dynamic loading, I don't think it is something in the loading. But there must be something missing in animateText and reloading functions that causes the issue.

Dealing with multiple animation state in one sprite sheet image using html5 canvas

I am recently creating a Game using html5 canvas .The player have multiple state it can walk jump kick and push and multiple other states my question is simple but after some deep research i couldn't find the best way to deal with those multiple states
this is my jsfiddle : http://jsfiddle.net/Z7a5h/5/
i managed to do one animation but i started my code in a messy way ,can anyone show me a way to deal with multiple state animation for one sprite image or just give a useful link to follow and understand the concept of it please .I appreciate your help
if (!this.IsWaiting) {
this.IsWaiting = true;
this.lastRenderTime = now;
this.Pos = 1 + (this.Pos + 1) % 3;
}
else {
if (now - this.lastRenderTime >= this.RenderRate) this.IsWaiting = false;
}
This is my animation class, which let's you set an animation and create the animation as object. I personally like to place the animations in an array such as playerAnimations[], and run the animations according to what the player does.
var toPix = function(n) {
return n*TILE; //tile is basically the same as sh or sw, but I used Tilesizes to draw things.
};
// Animations
var Sprite = function(image, sx, sy, sw, sh) {
this.img = image;
this.sx = sx;
this.sy = sy;
this.sw = sw;
this.sh = sh;
Sprite.prototype.draw = function(ctx, x, y) {
this.x = x;
this.y = y;
this.ctx = ctx;
this.ctx.drawImage(this.img, this.sx, this.sy, this.sw, this.sh, this.x, this.y, this.sw, this.sh);
};
};
var Animation = function(url, ctx, startingRow, rows, columns, sw, sh) {
this.ctx = ctx;
this.url = url;
this.startRow = toPix(startingRow - 1);
this.rows = rows;
this.columns = columns;
this.sprites = [];
animImg = new Image();
animImg.addEventListener('load', function() {});
animImg.src = this.url;
for(var i = 0; i < columns; i++) {
sprite = new Sprite(animImg, i*sw, this.startRow, sw, sh);
this.sprites.push(sprite);
}
this.spriteToDraw = 0;
this.drawSprite = 0;
this.drawSpriteTime = 10;
Animation.prototype.start = function() {
this.stopAnimation = false;
};
Animation.prototype.stop = function() {
this.stopAnimation = true;
};
Animation.prototype.draw = function(x, y) {
if(!this.stopAnimation) {
if(this.spriteToDraw < this.sprites.length) {
var sprite = this.sprites[this.spriteToDraw];
} else {
this.spriteToDraw = 0;
var sprite = this.sprites[this.spriteToDraw];
}
sprite.draw(this.ctx, x, y);
if(this.drawSprite > this.drawSpriteTime) {
this.spriteToDraw++;
this.drawSprite = 0;
} else {
this.drawSprite += 1;
}
}
};
};
//var animation = new Animation('theSprite.png', 5, 5, 45, 45);
//playerAnimations.push(animation);
And then this would be a sample player.draw() function.action.
What it does is: it checks which state the player is in, stops all other animations and runs the correct animation for that state.
player.prototype.draw = function() {
//player.draw function
if(this.playerRight) {
if (this.playerAnimation = playerAnimations[0]) {
this.playerAnimation.stop();
}
if (this.playerAnimation = playerAnimations[2]) {
this.playerAnimation.stop();
}
this.playerAnimation = playerAnimations[1];
this.playerAnimation.start();
this.playerAnimation.draw(this.x, this.y);
} else if(!this.playerRight && !this.playerLeft) {
if (this.playerAnimation = playerAnimations[1]) {
this.playerAnimation.stop();
}
if (this.playerAnimation = playerAnimations[2]) {
this.playerAnimation.stop();
}
this.playerAnimation = playerAnimations[0];
this.playerAnimation.start();
this.playerAnimation.draw(this.x, this.y);
} else {
if(this.playerLeft) {
if (this.playerAnimation = playerAnimations[0]) {
this.playerAnimation.stop();
}
if (this.playerAnimation = playerAnimations[1]) {
this.playerAnimation.stop();
}
this.playerAnimation = playerAnimations[2];
this.playerAnimation.start();
this.playerAnimation.draw(this.x, this.y);
}
};
I hope this is able to help you. This is my way of doing these kind of animations and it works for me, good luck!

Generating new canvas dynamically in javascript

I have a canvas that I can draw things what I want to do is generate new canvases dynamically when clicking a button.I've defined a generate function but it did not work
here is script
//<![CDATA[
window.addEventListener('load', function () {
// get the canvas element and its context
var canvas = document.getElementById('sketchpad');
var context = canvas.getContext('2d');
// create a drawer which tracks touch movements
var drawer = {
isDrawing: false,
touchstart: function (coors) {
context.beginPath();
context.moveTo(coors.x, coors.y);
this.isDrawing = true;
},
touchmove: function (coors) {
if (this.isDrawing) {
context.lineTo(coors.x, coors.y);
context.stroke();
}
},
touchend: function (coors) {
if (this.isDrawing) {
this.touchmove(coors);
this.isDrawing = false;
}
}
};
// create a function to pass touch events and coordinates to drawer
function draw(event) {
var type = null;
// map mouse events to touch events
switch(event.type){
case "mousedown":
event.touches = [];
event.touches[0] = {
pageX: event.pageX,
pageY: event.pageY
};
type = "touchstart";
break;
case "mousemove":
event.touches = [];
event.touches[0] = {
pageX: event.pageX,
pageY: event.pageY
};
type = "touchmove";
break;
case "mouseup":
event.touches = [];
event.touches[0] = {
pageX: event.pageX,
pageY: event.pageY
};
type = "touchend";
break;
}
// touchend clear the touches[0], so we need to use changedTouches[0]
var coors;
if(event.type === "touchend") {
coors = {
x: event.changedTouches[0].pageX,
y: event.changedTouches[0].pageY
};
}
else {
// get the touch coordinates
coors = {
x: event.touches[0].pageX,
y: event.touches[0].pageY
};
}
type = type || event.type
// pass the coordinates to the appropriate handler
drawer[type](coors);
}
// detect touch capabilities
var touchAvailable = ('createTouch' in document) || ('ontouchstart' in window);
// attach the touchstart, touchmove, touchend event listeners.
if(touchAvailable){
canvas.addEventListener('touchstart', draw, false);
canvas.addEventListener('touchmove', draw, false);
canvas.addEventListener('touchend', draw, false);
}
// attach the mousedown, mousemove, mouseup event listeners.
else {
canvas.addEventListener('mousedown', draw, false);
canvas.addEventListener('mousemove', draw, false);
canvas.addEventListener('mouseup', draw, false);
}
// prevent elastic scrolling
document.body.addEventListener('touchmove', function (event) {
event.preventDefault();
}, false); // end body.onTouchMove
}, false); // end window.onLoad
function generate(){
var newCanvas = document.createElement('canvas');
newCanvas.width = 400;
newCanvas.height = 400;
document.getElementById('container').appendChild(newCanvas);
ctx = newCanvas.getContext('2d');
}
//]]>
here is jsfiddle http://jsfiddle.net/regeme/WVUwn/
ps:drawing not displayed on jsfiddle however it works on my localhost I have totally no idea about it , anyway what I need is generate function , I did but I think I am missing something..
Any ideas? thanks..
Below is a function I wrote to dynamically create canvas.
If the canvas already exists (same ID) then that canvas is returned.
The pixelRatio parameter can be defaulted to 1. It's used for setting the correct size on retina displays (so for iPhone with Retina the value would be 2)
function createLayer(sizeW, sizeH, pixelRatio, id, zIndex) {
// *** An id must be given.
if (typeof id === undefined) {
return false;
}
// *** If z-index is less than zero we'll make it a buffer image.
isBuffer = (zIndex < 0) ? true : false;
// *** If the canvas exist, clean it and just return that.
var element = document.getElementById(id);
if (element !== null) {
return element;
}
// *** If no zIndex is passed in then default to 0.
if (typeof zIndex === undefined || zIndex < 0) {
zIndex = 0;
}
var canvas = document.createElement('canvas');
canvas.width = sizeW;
canvas.height = sizeH;
canvas.id = id;
canvas.style.width = sizeW*pixelRatio + "px";
canvas.style.height = sizeH*pixelRatio + "px";
canvas.style.position = "absolute";
canvas.style.zIndex = zIndex;
if (!isBuffer) {
var body = document.getElementsByTagName("body")[0];
body.appendChild(canvas);
}
return canvas;
}
Change the jsfiddle option
"onLoad"
to
"No Wrap - in <body>"
EDIT: See also similar question over here: Uncaught ReferenceError for a function defined in an onload function
JSFiddle options: http://doc.jsfiddle.net/basic/introduction.html#frameworks-and-extensions
This is the working update of your JSFIDDLE
javascript:
document.getElementById('generate').addEventListener('mousedown', generate, false);
I guess this is what you want.
I've just added an eventListener to your button in javascript code itself.
P.S.: I've also added black background color to canvas to show it on white background.

Draw on click or touch event

im learnig javascript and try to develop a page to draw on. Change colors and linewidth are already in place. Now it is drawing, but just when I move the mouse. I'd like to add also on click on just on move. So I'm able to draw also points. I have put the drawCircle function in the function stopDraw, but this is not working as it should. Any ideas?
Second problem is that, I'd like to draw a circle without stroke. But as soon as I change the lineWidth, also my circle gets a stroke around. Please help...
// Setup event handlers
cb_canvas = document.getElementById("cbook");
cb_lastPoints = Array();
if (cb_canvas.getContext) {
cb_ctx = cb_canvas.getContext('2d');
cb_ctx.lineWidth = 14;
cb_ctx.strokeStyle = "#0052f8";
cb_ctx.lineJoin="round";
cb_ctx.lineCap="round"
cb_ctx.beginPath();
cb_canvas.onmousedown = startDraw;
cb_canvas.onmouseup = stopDraw;
cb_canvas.ontouchstart = startDraw;
cb_canvas.ontouchend = stopDraw;
cb_canvas.ontouchmove = drawMouse;
}
function startDraw(e) {
if (e.touches) {
// Touch event
for (var i = 1; i <= e.touches.length; i++) {
cb_lastPoints[i] = getCoords(e.touches[i - 1]); // Get info for finger #1
}
}
else {
// Mouse event
cb_lastPoints[0] = getCoords(e);
cb_canvas.onmousemove = drawMouse;
}
return false;
}
// Called whenever cursor position changes after drawing has started
function stopDraw(e) {
drawCircle(e);
e.preventDefault();
cb_canvas.onmousemove = null;
}
//Draw circle
function drawCircle(e) {
var canvasOffset = canvas.offset();
var canvasX = Math.floor(e.pageX-canvasOffset.left);
var canvasY = Math.floor(e.pageY-canvasOffset.top);
//var canvasPos = getCoords(e);
cb_ctx.beginPath();
cb_ctx.arc(canvasX, canvasY, cb_ctx.lineWidth/2, 0, Math.PI*2, true);
cb_ctx.fillStyle = cb_ctx.strokeStyle;
cb_ctx.fill();
}
function drawMouse(e) {
cb_ctx.beginPath();
if (e.touches) {
// Touch Enabled
for (var i = 1; i <= e.touches.length; i++) {
var p = getCoords(e.touches[i - 1]); // Get info for finger i
cb_lastPoints[i] = drawLine(cb_lastPoints[i].x, cb_lastPoints[i].y, p.x, p.y);
}
}
else {
// Not touch enabled
var p = getCoords(e);
cb_lastPoints[0] = drawLine(cb_lastPoints[0].x, cb_lastPoints[0].y, p.x, p.y);
}
cb_ctx.stroke();
cb_ctx.closePath();
//cb_ctx.beginPath();
return false;
}
// Draw a line on the canvas from (s)tart to (e)nd
function drawLine(sX, sY, eX, eY) {
cb_ctx.moveTo(sX, sY);
cb_ctx.lineTo(eX, eY);
return { x: eX, y: eY };
}
// Get the coordinates for a mouse or touch event
function getCoords(e) {
if (e.offsetX) {
return { x: e.offsetX, y: e.offsetY };
}
else if (e.layerX) {
return { x: e.layerX, y: e.layerY };
}
else {
return { x: e.pageX - cb_canvas.offsetLeft, y: e.pageY - cb_canvas.offsetTop };
}
}
Your drawCircle function is wrapped in the canvas's onclick event. It should be
function drawCircle(e) {
var canvasOffset = canvas.offset();
var canvasX = Math.floor(e.pageX-canvasOffset.left);
var canvasY = Math.floor(e.pageY-canvasOffset.top);
cb_ctx.beginPath();
cb_ctx.lineWidth = 0;
cb_ctx.arc(canvasX,canvasY,cb_ctx.lineWidth/2,0,Math.PI*2,true);
cb_ctx.fillStyle = cb_ctx.strokeStyle;
cb_ctx.fill();
}
So you'll have to pass the event object from stop draw as well
function stopDraw(e) {
drawCircle(e); //notice the change here
e.preventDefault();
cb_canvas.onmousemove = null;
}
Note that you're also setting you circle's radius to 0 which might be another reason why it's not showing up.
cb_ctx.lineWidth = 0;
cb_ctx.arc(canvasX,canvasY,cb_ctx.lineWidth/2,0,Math.PI*2,true);
0 divided by 2 is always zero. If you don't want to stroke around the circle just don't call stroke(). the drawCircle function isn't causing that, since there's a beginPath() call. I suspect it's because you don't beginPath() before calling stroke() in drawMouse.

Categories