how to add mouse pointer position to custom mouse pointer in createjs - javascript

Here I custom my mouse pointer to circle on that circle I want mouse pointer. Initially mouse pointer is on circle but when I moved mouse on stage mouse pointer is not on exact position on circle. 3
How to get exact position of each?
var cursor;
createjs.Touch.enable(stage);
stage.enableMouseOver();
cursor = new createjs.Shape(new createjs.Graphics().beginFill("#000000").drawCircle(0, 0, 25));
cursor.cursor = "pointer";
stage.addChild(cursor);
stage.addEventListener("stagemousemove", handleMouseMove);
stage.update();
function handleMouseMove(event) {
cursor.x = stage.mouseX;
cursor.y = stage.mouseY;
stage.update();
}

Can you clarify your question?
Here is a fiddle of your code: http://jsfiddle.net/j6erzwgn/1/
I removed the "updateStage" call from your handleMouseMove, and put it in a ticker event, since mouse events fire a lot faster than the stage needs.
I changed the Ticker to use RAF so it is nice and smooth.
Here is a sample
createjs.Ticker.on("tick", stage);
createjs.Ticker.timingMode = createjs.Ticker.RAF;
It seems to run fine. If you notice a slight delay, that is somewhat expected with custom cursors, since they aren't updated in synch with the system cursor.
Does that help? I am not sure what your other questions are asking.

Related

Pan Zoom behaviour using EaselJS

I’m having some trouble incorporating pan/zoom behaviour with the ability to also drag-move some shapes around on the canvas, using EaselJS.
I want to be able to move the shape ONLY if I mousedown on it, but if I mousedown on the stage (i.e. not on a shape), then I want to be able to pan the stage.
This behaviour needs to be consistent regardless of the ‘zoom’ level (which is altered by the mousewheel).
I have read this: How to stop the event bubble in easljs? Which suggests that the stage mousedown events will fire regardless of whether I have clicked on a shape or empty space, so it would be better to create a ‘background’ shape to capture my mousedown events that are not on a ‘proper’ shape.
This fiddle is how I have set it up: https://jsfiddle.net/hmcleay/mzheuLbg/
var stage = new createjs.Stage("myCanvas");
console.log('stage.scaleX: ', stage.scaleX);
console.log('stage.scaleY: ', stage.scaleY);
function addCircle(r,x,y){
var g=new createjs.Graphics().beginFill("#ff0000").drawCircle(0,0,r);
var s=new createjs.Shape(g)
s.x=x;
s.y=y;
s.on('pressmove', function(ev) {
var localpos = stage.globalToLocal(ev.stageX, ev.stageY)
s.x = localpos.x;
s.y = localpos.y;
stage.update();
});
stage.addChild(s);
stage.update();
}
// create a rectangle 'background' Shape object to cover the stage (to allow for capturing mouse drags on anything except other shapes).
bg = new createjs.Shape();
bg.graphics.beginFill("LightGray").drawRect(10, 10, stage.canvas.width - 20, stage.canvas.height - 20); //deliberately smaller for debugging purposes (easier to see if it moves).
bg.x = 0;
bg.y = 0;
stage.addChild(bg);
stage.update();
//create a rectangle frame to represent the position of the stage.
stageborder = new createjs.Shape();
stageborder.graphics.beginStroke("Black").drawRect(0, 0, stage.canvas.width, stage.canvas.height);
stageborder.x = 0;
stageborder.y = 0;
stage.addChild(stageborder);
stage.update();
// MOUSEWHEEL ZOOM LISTENER - anywhere on canvas.
var factor
canvas.addEventListener("wheel", function(e){
if(Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)))>0){
factor = 1.1;
} else {
factor = 1/1.1;
}
var local = stage.globalToLocal(stage.mouseX, stage.mouseY);
stage.regX=local.x;
stage.regY=local.y;
stage.x=stage.mouseX;
stage.y=stage.mouseY;
stage.scaleX = stage.scaleX * factor;
stage.scaleY = stage.scaleY * factor;
//re-size the 'background' shape to be the same as the canvas size.
bg.graphics.command.w = bg.graphics.command.w / factor;
bg.graphics.command.h = bg.graphics.command.h / factor;
// re-position the 'background' shape to it's original position of (0,0) in the global space.
var localzero = stage.globalToLocal(0, 0);
bg.x = localzero.x;
bg.y = localzero.y;
stage.update();
});
// listener to add circles to the canvas.
canvas.addEventListener('dblclick', function(){
var localpos = stage.globalToLocal(stage.mouseX, stage.mouseY);
addCircle(10, localpos.x, localpos.y);
});
bg.addEventListener("mousedown", function(ev1){
// purpose of this listener is to be able to capture drag events on the 'background' to pan the whole stage.
// it needs to be a separate 'shape' object (rather than the stage itself), so that it doesn't fire when other shape objects are drag-moved around on the stage.
// get the initial positions of the stage, background, and mousedown.
var mousedownPos0 = {'x': ev1.stageX, 'y': ev1.stageY};
var stagePos0 = {'x': stage.x, 'y': stage.y};
var bgPos0 = {'x': bg.x, 'y': bg.y};
bg.addEventListener('pressmove', function(ev2){
//logic is to pan the stage, which will automatically pan all of it's children (shapes).
// except we want the 'background' shape to stay where it is, so we need to offset it in the opposite direction to the stage movement so that it stays where it is.
stageDelta = {'x': ev2.stageX - mousedownPos0.x, 'y': ev2.stageY - mousedownPos0.y};
//adjust the stage position
stage.x = stagePos0.x + stageDelta.x;
stage.y = stagePos0.y + stageDelta.y;
// return the 'background' shape to global(0,0), so that it doesn't move with the stage.
var localzero = stage.globalToLocal(0,0);
bg.x = localzero.x;
bg.y = localzero.y;
stage.update();
});
});
The grey box is my background shape. I have deliberately made it slightly smaller than the canvas, so that I can see where it is (useful for debugging).
Double click anywhere on the canvas to add some red circles.
If you drag a circle, it only moves that circle.
If you drag on the grey ‘background’ area in between circles, it moves the whole stage (and therefore all the child shapes belonging to the stage).
Because the grey background is also a child of the stage, it wants to move with it. So I have included some code to always return that grey box back to where it started.
The black border represents the position of the ‘stage’, I just added it to help visualise where the stage is.
The mousewheel zoom control is based on the answer to this question: EaselJS - broken panning on zoomed image
Similar to drag-panning, when zooming I have to adjust the size and position of the grey ‘background’ box so that it renders in the same position on the canvas.
However, it doesn’t stay exactly where I want it to… it seems to creep up towards the top left corner of the canvas when I zoom out.
I’ve spent quite some time trying to diagnose this behaviour and can’t find out why it’s happening. I suspect it may have something to do with rounding.. but I’m really not sure.
Can anyone explain why my grey box isn't staying stationary when I zoom in and out?
An alternative method would be to scrap the ‘background’ shape used for capturing mousedown events that aren’t on a ‘proper’ shape.
Instead, it might be possible to use the ‘stage’ mousedown event, but prevent it from moving the stage if the mouse is over a ‘shape’.
Would this be a better way of handling this behaviour? Any suggestions how to prevent it from moving the stage?
Thanks in advance,
Hugh.
Ok,
So as usually happens, after finally asking for help, I managed to work out the problem.
The issue was caused by making the background shape (grey rectangle) 10px smaller than the canvas, so that I could see its position more clearly (to assist with debugging). How ironic that this offset was causing the issue.
The 10px offset was not being converted into the 'local' space when the zoom was applied.
By making the grey rectangle's graphic position at (0,0) with width and height equal to that of the canvas, the problem went away!
Hope this is of use to someone at some point in time.
Cheers,
Hugh.

How do I make a HTML canvas rectangle resize along with mouse drag?

I am creating a web-based annotation application for annotating images via the HTML canvas element and Javascript. I would like the user to mouse down to indicate the start of the rectangle, drag to the desired end coordinate and let go to indicate the opposite end of the rectangle.
Currently, I am able to take the starting coordinates and end coordinates to create a rectangle on the image with the context.rects() function, however as I am uncertain on how to resize a specific rectangle on the canvas, that leaves me with the rectangle only being drawn after the user has released the mouse click.
How would I be able to resize a specific rectangle created onmousedown while dragging?
The following is the code snippet that performs the function:
var isMouseDown = false;
var startX;
var startY;
canvas.onmousedown = function(e) {
if(annMode){
isMouseDown = true;
var offset = $(this).offset();
startX = parseInt(e.pageX - offset.left);
startY = parseInt(e.pageY - offset.top);
}
};
canvas.onmousemove = function(e) {
if(isMouseDown) {
var offset = $(this).offset();
var intermediateX = parseInt(e.pageX - offset.left);
var intermediateY = parseInt(e.pageY - offset.top);
console.log(intermediateX);
}
};
canvas.onmouseup = function(e) {
if(annMode&&isMouseDown){
isMouseDown = true;
var offset = $(this).offset();
var endX = parseInt(e.pageX - offset.left);
var endY = parseInt(e.pageY - offset.top);
var width = endX - startX;
var height = endY - startY;
context.strokeStyle = "#FF0000";
context.rect(startX, startY, width, height);
context.stroke();
}
isMouseDown = false
};
Here my handy-front-end scripts come in handy!
As I understood the question, you wanted to be able to move your mouse to any point on the canvas, hold the left mouse button, and drag in any direction to make a rectangle between the starting point and any new mouse position. And when you release the mouse button it will stay.
Scripts that will help you accomplish what you are trying to do:
https://github.com/GustavGenberg/handy-front-end/blob/master/README.md#canvasjs
https://github.com/GustavGenberg/handy-front-end/blob/master/README.md#pointerjs
Both scripts just makes the code a lot cleaner and easier to understand, so I used those.
Here is a fiddle as simple as you can make it really using
const canvas = new Canvas([]);
and
const mouse = new Pointer();
https://jsfiddle.net/0y8cbao3/
Did I understand your question correctly?
Do you want a version with comments describing every line and what is does?
There are still some bugs at the moment but im going to fix those soon!
EDIT
After reading your questions again, I reacted to: "...however as I am uncertain on how to resize a specific rectangle on the canvas...".
Canvas is like an image. Once you have drawn to it, you can NOT "resize" different shapes. You can only clear the whole canvas and start over (ofcourse you can clear small portions too).
That's why the Canvas helper is so helpful. To be able to "animate" the canvas, you have to create a loop that redraws the canvas with a new frame each 16ms (60 fps).
The canvas API does not preserve references to specific shapes drawn with it (unlike SVG). The canvas API simply provides convenient functions to apply operations to the individual pixels of the canvas element.
You have a couple options to achieve a draggable rectangle:
You can position a styled div over your canvas while the user is dragging. Create a container for your canvas and the div, and update the position and size the div. When the user releases, draw your rectangle. Your container needs to have position: relative and the div needs to be absolutely positioned. Ensure the div has a higher z-index than the canvas.
In your mouse down method, set div.style.display to block. Then update the position (style.left, style.top, style.width, and style.height) as the mouse is dragged. When the mouse is released, hide it again (style.display = 'none').
You can manually store references to each item you want to draw, clear the canvas (context.clearRect), and redraw each item on the canvas each frame. This kind of setup is usually achieved through recursive usage of the window.requestAnimationFrame method. This method takes a callback and executes on the next draw cycle of the browser.
The first option is probably easier to achieve in your case. If you plan to expand the capabilities of your app further, the 2nd will provide more versatility. A basic loop would be implemented as so:
// setup code, create canvas & context
function mainLoop() {
context.clearRect(0, 0, canvas.width, canvas.height);
/** do your logic here and re-draw **/
requestAnimationFrame(mainLoop);
}
function startApp() {
requestAnimationFrame(mainLoop)
}
This tutorial has detailed explanation of event loops for HTML canvas: http://www.isaacsukin.com/news/2015/01/detailed-explanation-javascript-game-loops-and-timing
I also have a fully featured implementation on my GitHub that's part of rendering engine I wrote: https://github.com/thunder033/mallet/blob/master/src/mallet/webgl/webgl-app.ts#L115

Add Mouse pointer on movieclip In Animate CC canvas

I am trying to use a movieclip as a button, but the mouse cursor will not show on hover or on click...I have tried the answer on stack overflow, to add the movieClip.cursor = "pointer"; to the top of the code, but in my case there is no mouse pointer, (nor in Mozilla, nor in Chrome...)
In as 3.0 I used to use: buttonMode ="true", why does ...cursor = "pointer" not work in canvas/html5...it is a simple code..?
here is my code
this.stop();
this.shape_mc.cursor = "pointer";
this.shape_mc.addEventListener("click", fl_MouseClickHandler.bind(this));
function fl_MouseClickHandler()
{
this.play();
}

Drawing mouse selection area (rubber band) with Pixi.js / html Canvas

I have a pixi.js html canvas with thousands of objects on it and I want the user to be able to zoom into it with the usual rectangular selection area. The brute force way to implement this would be to draw the rectangle on each mouse move and rerender the whole stage. But this seems like a waste of CPU. Plus this is so common in user interfaces, that I suspect that there is already some function in pixi.js or a plugin that solves this.
If there is no plugin: If I could save the whole buffer to some 2nd buffer when the user presses the mouse button, I could draw the rectangle on top, and on every mouse move, copy back the 2nd buffer to the primary buffer before drawing the rectangle. This would mean that I didn't have to redraw everything on every mouse move. But I don't think that one can clone the current buffer to some named secondary buffer.
Another alternative would be to move a rectangular DOM object on top of the canvas, but then I am afraid that the current pixel position will be hard to relate to the pixi.js / html5 canvas pixels.
Is there a better way? Or some plugin / search engine keyword that I'm missing? How would you implement a rubber band in html canvas or pixi.js ?
I ended up solving this with a separate DOM object that is moved over the canvas. The solution also requires the new interaction manager in PIXI 4, that offers a single callback for any mouse movement over the canvas.
In the following, I assume that the canvas is placed at canvasLeft and canvasTop pixels with CSS.
$(document.body).append("<div style='position:absolute; display:none; border: 1px solid black' id='tpSelectBox'></div>");
renderer = new PIXI.CanvasRenderer(0, 0, opt);
// setup the mouse zooming callbacks
renderer.plugins.interaction.on('mousedown', function(ev) {
mouseDownX = ev.data.global.x;
mouseDownY = ev.data.global.y; $("#tpSelectBox").css({left:mouseDownX+canvasLeft, top:mouseDownY+canvasTop}).show();
});
renderer.plugins.interaction.on('mousemove', function(ev) {
if (mouseDownX == null)
return;
var x = ev.data.global.x;
var y = ev.data.global.y;
var selectWidth = Math.abs(x - mouseDownX);
var selectHeight = Math.abs(y - mouseDownY);
var minX = Math.min(ev.data.global.x, mouseDownX);
var minY = Math.min(ev.data.global.y, mouseDownY);
var posCss = {
"left":minX+canvasLeft,
"top":minY+canvasTop,
"width":selectWidth,
"height":selectHeight
};
$("#tpSelectBox").css(posCss);
});
renderer.plugins.interaction.on('mouseup', function(ev) {
$("#tpSelectBox").hide();
mouseDownX = null;
mouseDownY = null;
$("#tpSelectBox").css({"width":0, "height":0});
});
For older version of PIXI, here is an example of pan/zoom without a rectangle
https://github.com/Arduinology/Pixi-Pan-and-Zoom/blob/master/js/functions.js
In May 2015, the Interaction Manager got extended to allow easier pan/zoom handling https://github.com/pixijs/pixi.js/issues/1825 which is what I'm using here.

How to write "drag" event for objects on canvas?

(i correct the mousedown thing..)
What i want to realize is to drag a ball on the canvas and then the ball will follow the mouse and change its color.
Once the mouse releases it, its color turns back to original.
i use "break" because only one ball could be dragged at one time.
Now the problem is,
"drag" seems weird, it seems "dragging" the first ball, but only mousemove(no mouse press) is ok right after the first ball.
the color doesn't change
main function below (complete code here http://jsfiddle.net/nyTkU/1/):
var mousePress = false;
var mouseEvent = function(){
$(canvas).mousedown(function(e){
mousePress = true;
$(canvas).mousemove(function(e){
for(var i=0;i<figureNum;i++){
var distX=e.pageX-balls[i].x;
var distY=e.pageY-balls[i].y;
var distance = Math.sqrt((distX*distX)+(distY*distY));
if(distance<=20){
balls[i].x=e.pageX;
balls[i].y=e.pageY;
if(mousePress){
balls[i].c="#F05133";
}
break;
}
//else{balls[i].c="#FFED79";}
}
});
});
$(canvas).mouseup(function(e){
mousePress=false;
//for(var i=0;i<figureNum;i++){
// balls[i].c="#FFED79";
//}
})
setTimeout(animate,speedMouse);
}
Many many thanks.
You have two mouseDown events...maybe the second one should be mouseUp?
I'm still a little confused on your desired functionality. Do you want the ball to move only if mouseDown=true or a ball should move if it is clicked once? Because you should be using click() handler in the second case.
Your mouseMove seems odd as well...are you trying to get any ball within a certain distance D to bind to the mouse coordinates? That will create some odd behavior.
Best way to do this would be:
1) On mouseDown, detect if a ball has been selected and save that ID. (set mousePressed=true)
2) On mouseMove, if mousePressed=true && ball is selected, bind that ball to the mouse coordinates. Do not update() this ball with any velocity.
3) On mouseUp, set mousePressed=false and clear any selected Ball

Categories

Resources