I want to have two event handlers.
one is when I click on the canvas based on mouseX an mouseY an image appears at a certain position (snap to grid).
The second is when I click on the same image that appeared I want this image to be removed.
The first event handler is implemented and work well the second doesn't work how can I make this happen?
Also I guess that when I want to remove my image the first event handler triggers and add a new image it's a vicious circle.
Here is my addImage() function:
function addImage(spaceX, spaceY, mouseX, mouseY, sizeX, sizeY, url) {
//spaceX/Y is the size of my grid
//mouseX/Y are the coordinates of my mouse
//sizeX/Y is the size of my canvas
//url is the url of my image.
fabric.Image.fromURL(url, function(oImg) {
var divX = sizeX / spaceX;
var resX = mouseX / sizeX * divX;
var indW = Math.trunc(resX); //X index in the grid
var divY = sizeY / spaceY;
var resY = mouseY / sizeY * divY;
var indH = Math.trunc(resY); //Y index in the grid
oImg.top = indH * spaceY;
oImg.left = indW * spaceX;
oImg.scaleToWidth(spaceX);
oImg.scaleToHeight(spaceY);
oImg.selectable = false;
//this is my non-working function to remove my image.
oImg.on('click', function() {
canvas.getActiveObject().remove();
})
canvas.add(oImg);
});
}
oImg.on('mousedown', function (){
canvas.remove(this);
})
use mousedown event for object.
DEMO
var canvas = new fabric.Canvas('canvas');
fabric.Image.fromURL('http://fabricjs.com/assets/pug.jpg', function(oImg) {
oImg.on('mousedown', function (){
canvas.remove(this);
})
canvas.add(oImg);
});
canvas{
border:2px solid #000;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id='canvas' width=500 height=400>
I have a Sharepoint page in which i want to show a hierarchical diagram with boxes.According to my requirement those boxes should work as links to other sharepoint pages in the same site.
Since sharepoint's default designer tools doesn't support designing such diagrams, I created a page with html5 canvas and the element i wanted inside that.
Inside the canvas i created few boxes and lines to connect them.And i added texts inside the boxes.Then i used a mouse listener to check whether the mouse pointer hovers over a box and if so changed the pointer icon and the link to be redirected to.
I added the canvas tag inside the sharepoint page by "Edit Source" and i added the javascript part using 'Embed Code'
Now the code works perfectly in IE and Firefox.
In chrome although the boxes,lines and text are drawn according to the coordinates i gave in the code but But when i hover the mouse over them it gives different coordinates for mouse listener in different browser sizes.So the mouse pointer doesn't change at correct locations ie: over the boxes.
This doesn't happen in firefox or IE. They changes the mouse pointer when it comes over the boxes and links to the pages perfectly.
Why does it change when i use chrome?
And why does it only affect to the mouse listener coordinates.
This is the code i used.(I have removed the repetitive parts which draws other boxes)
Same in jsfiddle
<canvas id="myCanvas" height="500" width="960" style="border: 1px solid;"><img src="" alt=""/> </canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx;
var rNBDX = 50; var rNBDY = 150;
var rectWidth = 200;
var rectHeight = 100;
var cornerRadius = 20;
var linkNBD="https://google.com";
var textNBD1 ="Google";
var linkHeight=20;
var linkNum = 0;
function draw(){
canvas = document.getElementById("myCanvas");
if(canvas.getContext){
ctx=canvas.getContext("2d");
//Drawing Lines
ctx.lineWidth = 3;
ctx.strokeStyle = '#000000';
ctx.moveTo(380, 100);
ctx.lineTo(380, 125);
ctx.stroke();
//Drawing Rectangles
ctx.fillStyle="#0b61d0";
ctx.strokeStyle="#0b61d0";
ctx.lineJoin = "round";
ctx.lineWidth = cornerRadius;
ctx.strokeRect(rNBDX+(cornerRadius/2), rNBDY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
ctx.fillRect(rNBDX+(cornerRadius/2), rNBDY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
//Drawing the Texts
ctx.font='24px Segoe UI Light';
ctx.fillStyle = "#FFFFFF";
ctx.fillText(textNBD1,(rNBDX+rectWidth/2)-(ctx.measureText(textNBD1).width)/2,rNBDY+rectHeight/2);
//Add mouse listeners
canvas.addEventListener("mousemove", on_mousemove, false);
canvas.addEventListener("click", on_click, false);
}
}
function on_mousemove (ev) {
var x, y;
if (ev.layerX || ev.layerX == 0) {
x = ev.layerX;
y = ev.layerY;
}
x-=canvas.offsetLeft;
y-=canvas.offsetTop;
if(x>=rNBDX && x <= (rNBDX + rectWidth) && y>=rNBDY && y<= (rNBDY+rectHeight)){
document.body.style.cursor = "pointer";
linkNum=1;
}
else{
document.body.style.cursor = "";
}
}
function on_click(e) {
switch (linkNum)
{
case 1:
window.location = linkNBD;
break;
}
}
draw();
</script>
Try adjusting the mouse coordinates like this:
function on_mousemove (ev) {
var x, y,
rect = canvas.getBoundingClientRect();
x = ev.clientX - rect.left + 1;
y = ev.clientY - rect.top + 1;
...
You will have to add (as in the example) the width of the left/top border though as getBoundingClientRect does not include those (you can calculate this dynamically using getComputedStyle and getPropertyValue of that for the borders).
I'm trying to get an event to work on an image when the user clicks on it.
var canvas = document.createElement("canvas");
canvas.width = 800;
canvas.height = 600;
canvas.style = "border:2px solid black";
canvas.addEventListener('click', clickReporter, false);
var ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
var clickhere = new Image();
clickhere.onload = function () {
draw();
};
clickhere.src = "clickhere.png";
function draw() {
ctx.drawImage(clickhere, 200, 200);
}
function clickReporter(e) {
alert("Thanks for clicking!");
}
Obviously all this code will just let the alert box go off as long as the user clicks in the canvas. The image is 100 by 100 pixels.
First off: You apparently have an error in you code in regards to the image (at least in the example you provide):
var button = new Image();
clickhere.onload = function () {
draw();
};
clickhere.src = "clickhere.png";
function draw() {
ctx.drawImage(clickhere, 200, 200);
}
Should be like this for the example to work:
var button = new Image();
/// use button for these as well -
button.onload = function () { /// here
draw();
};
button.src = "clickhere.png"; /// here
function draw() {
ctx.drawImage(button, 200, 200); /// and here (or use 'this' instead)
}
The next problem
Canvas doesn't know what we draw into it so we need to make sure we provide all the underlying logic ourselves to handle these sort of things.
For example: Here is one way to check if the region the image was drawn into is clicked:
function clickReporter(e) { /// assign event to some variable
/// adjust mouse click position to be relative to canvas:
var rect = this.getBoundingClientRect(),
x = e.clientX - rect.left,
y = e.clientY - rect.top;
/// check x/y coordinate against the image position and dimension
if (x >= 200 && x <= (200 + button.width) &&
y >= 200 && y <= (200 + button.height)) {
alert("Thanks for clicking!");
}
}
You might want to convert those semi-absolute bounds to something more dynamic by for example using an image with a custom object where you store its x and y position and so forth. But you should get the idea.
Update:
A modified fiddle here
I have a webpage with an HTML5 canvas which I'm using to display a number of images as well as four 'description boxes' on the canvas.
The intention is that users will be able to drag and drop the images to their matching description boxes, however, I'm having a bit of trouble getting the dragging and dropping working.
The function I've written to add the drag and drop functionality is based on the tutorial I found at this page: http://simonsarris.com/blog/510-making-html5-canvas-useful
Obviously, I altered the code slightly, as I don't want to do everything suggested in the tutorial, and because I'm drawing images (not shapes) to the canvas. However, when viewing my page in the browser although all of the images are displayed on the canvas, the drag and drop functionality has not been added along with the new JavaScript file I've written based on that tutorial.
I'm not getting any errors in the Firebug console, and the page is displaying exactly as it was before I added the new JS function.
Can anyone spot what I'm missing?
My HTML is:
<!DOCTYPE html>
<html>
<head>
<script src = "kinetic.js" type = "text/javascript"></script>
<title>Home</title>
<script src = "drawLevelOneElements.js" type = "text/javascript"></script>
<script src = "layers&analytics.js" type = "text/javascript"></script>
<script src = "startGameDrawGameElementsDrawStartButton.js" type = "text/javascript"></script>
<script src = "interaction.js" type = "text/javascript"></script>
<script src = "dragAndDrop.js" type = "text/javascript"></script>
</head>
<body onLoad="startGame()">
<section hidden>
<img id="StartButton" src="StartButton.png" alt="Start Button" width="179" height="180" href="javascript:drawLevelOneElements();"/>
</section>
<h1>Home</h1>
<p>The purpose of this website is to teach users the basic principles of running a business by playing the game below. <br /><br /></p>
<canvas id="gameCanvas" width="1000" height="500" style="border:1px solid">
Your browser does not support the canvas element.
</canvas>
<br /><br />
<p>Use this paragraph to enter text that provides the user with instructions for how to play the game. <br />
Update the instructions so that they're appropriate to whatever level the user is currently playing.</p>
<script src = "layers&analytics.js" type = "text/javascript"></script>
<script src = "startGameDrawGameElementsDrawStartButton.js" type = "text/javascript"></script>
<script src = "variables&preloadingImages.js" type = "text/javascript"></script>
<script src = "drawLevelOneElements.js" type = "text/javascript"></script>
<script src = "interaction.js" type = "text/javascript"></script>-->
<script src = "variables&preloadingImages.js" type = "text/javascript"></script>
</body>
All of the script tags at the bottom of the page (except the last one) are actually commented out in my file, I just had to remove the comment to get it to display in a code block on here.
The javaScript I've added for the drag and drop functionality is:
function canvasState(myGameCanvas){
var bounding_box = myGameCanvas.getBoundingClientRect();
var mouseX = (mouse_event.clientX-bounding_box.left) * (myGameCanvas.width/bouding_box.width);
var mouseY = (mouse_event.clientY-bounding_box.top) * (myGameCanvas.height/bounding_box.height);
var pixels = context.getImageData(mouseX, mouseY, 1, 1);
this.valid = false; /*When set to true, the canvas will redraw everything */
this.allImagesArray; /*This is the array holding all of the images to be drawn */
this.dragging = false; /*Keep track of when the current selected object is being dragged */
this.selection = null;
this.dragOffX = 0; /*See mousedown and mousemove events for explanation */
this.dragOffY = 0;
this.interval = 30; /*This variable will be used to determine how often the draw method is called. */
/*Save a reference to the canvasState so that I'm still using this particular canvasState. */
var myState = this;
/*This stops double clicking on the canvas selecting text on the canvas */
myGameCanvas.addEventListener('selectstart', function(e) {e.preventDefault(); return false; }, false);
/*Up, down and move are for dragging */
myGameCanvas.addEventListener('mousedown', function(e){
var mouse = myState.getMouse(e);
var mX = mouse.x;
var mY = mouse.y;
var allImages = myState.allImagesArray;
var NoOfImages = allImages.length;
for (var i = 1-1; i >= 0; i--){
if(allImages[i].contains(mX, mY)){
var mySelection = allImages[i];
/*Keep track of where in the object was clicked, so that it can be
moved smoothly (see mousemove) */
myState.dragOffX = mX - mySelection.x;
myState.dragOffY = mY - mySelection.y;
myState.dragging = true;
myState.selection = mySelection;
myState.valid = false;
return;
}
}
/*If the code hasn't returned, it means that nothing has been selected.
If there was an object selected, then deselect it. */
if (myState.selection){
myState.selection = null;
myState.valid = false; /*Need to clear the old selection border */
}
}, true);
/*This event checks to see if the dragging flag has been set to true. If it has, it gets the
current mouse position and moves the selected object to that position, remembering the offset
where it was selected. If the dragging flag is false, the event does nothing. */
myGameCanvas.addEventListener('mousemove', function(e){
if(myState.dragging){
var mouse = myState.getMouse(e);
/*I don't want to drag the object by its top left corner, I want to drag from where the
object was clicked. That's why I saved the offset and use it here. */
myState.selection.x = mouse.x - myState.dragOffX;
myState.selection.y = mouse.y - myState.dragOffY;
myState.valid = false; /*Something's dragging, so I must redraw */
}
}, true);
/*All the mouseup event has to do is update the canvas state so that it is no longer dragging.
So, once the mouse button is lifted, the mousemove event should be back to doing nothing. */
myGameCanvas.addEventListener('mouseup', function(e){
myState.dragging = false;
}, true);
setInterval(function(){ myState.draw(); }, myState.interval);
canvasState.prototype.draw = function(){
/*If the state is invalid,redraw and validate. */
if (!this.valid){
var context = this.context;
var images = this.images;
this.clear();
/*Redraw the game elements here */
drawLevelOneElements();
}
}
}
Code for dragAndDrop.js:
function canvasState(myGameCanvas){
var bounding_box = myGameCanvas.getBoundingClientRect();
var mouseX = (mouse_event.clientX-bounding_box.left) * (myGameCanvas.width/bouding_box.width);
var mouseY = (mouse_event.clientY-bounding_box.top) * (myGameCanvas.height/bounding_box.height);
var pixels = context.getImageData(mouseX, mouseY, 1, 1);
this.valid = false; /*When set to true, the canvas will redraw everything */
this.allImagesArray; /*This is the array holding all of the images to be drawn */
this.dragging = false; /*Keep track of when the current selected object is being dragged */
this.selection = null;
this.dragOffX = 0; /*See mousedown and mousemove events for explanation */
this.dragOffY = 0;
this.interval = 30; /*This variable will be used to determine how often the draw method is called. */
/*Save a reference to the canvasState so that I'm still using this particular canvasState. */
var myState = this;
/*This stops double clicking on the canvas selecting text on the canvas */
myGameCanvas.addEventListener('selectstart', function(e) {e.preventDefault(); return false; }, false);
console.log("Event Listener 'selectstart' added to canvas.");
/*Up, down and move are for dragging */
myGameCanvas.addEventListener('mousedown', function(e){
console.log("Event Listener 'mousedown' added to canvas");
var mouse = myState.getMouse(e);
var mX = mouse.x;
var mY = mouse.y;
var allImages = myState.allImagesArray;
var NoOfImages = allImages.length;
for (var i = 1-1; i >= 0; i--){
if(allImages[i].contains(mX, mY)){
var mySelection = allImages[i];
/*Keep track of where in the object was clicked, so that it can be
moved smoothly (see mousemove) */
myState.dragOffX = mX - mySelection.x;
myState.dragOffY = mY - mySelection.y;
myState.dragging = true;
myState.selection = mySelection;
myState.valid = false;
return;
}
}
/*If the code hasn't returned, it means that nothing has been selected.
If there was an object selected, then deselect it. */
if (myState.selection){
myState.selection = null;
myState.valid = false; /*Need to clear the old selection border */
}
}, true);
/*This event checks to see if the dragging flag has been set to true. If it has, it gets the
current mouse position and moves the selected object to that position, remembering the offset
where it was selected. If the dragging flag is false, the event does nothing. */
myGameCanvas.addEventListener('mousemove', function(e){
console.log("Event listener 'mousemove' added to canvas.");
if(myState.dragging){
var mouse = myState.getMouse(e);
/*I don't want to drag the object by its top left corner, I want to drag from where the
object was clicked. That's why I saved the offset and use it here. */
myState.selection.x = mouse.x - myState.dragOffX;
myState.selection.y = mouse.y - myState.dragOffY;
myState.valid = false; /*Something's dragging, so I must redraw */
}
}, true);
/*All the mouseup event has to do is update the canvas state so that it is no longer dragging.
So, once the mouse button is lifted, the mousemove event should be back to doing nothing. */
myGameCanvas.addEventListener('mouseup', function(e){
console.log("Event listener 'mouseup' added to canvas.");
myState.dragging = false;
}, true);
setInterval(function(){ myState.draw(); }, myState.interval);
canvasState.prototype.draw = function(){
/*If the state is invalid,redraw and validate. */
if (!this.valid){
var context = this.context;
var images = this.images;
this.clear();
/*Redraw the game elements here */
drawLevelOneElements();
}
}
}
Code for drawLevelOneElements.js: (this now includes the call to canvasState(); )
function drawLevelOneElements(){
/*First, clear the canvas */
context.clearRect(0, 0, myGameCanvas.width, myGameCanvas.height);
/*This line clears all of the elements that were previously drawn on the canvas. */
/*Then redraw the game elements */
drawGameElements();
/*Call the function to enable drag and drop */
canvasState(document.getElementById('gameCanvas'));
/*Create the four description areas, and place them near the bottom of the canvas */
/*Create boxes with rounded corners for the description areas */
CanvasRenderingContext2D.prototype.drawDescriptionArea = function(x, y, width, height, radius, stroke){
if(typeof stroke == "undefined" ){
stroke = true;
}
if(typeof radius === "undefined"){
radius = 5;
}
this.beginPath();
this.moveTo(x + radius, y);
this.lineTo(x + width - radius, y);
this.quadraticCurveTo(x + width, y, x + width, y + radius);
this.lineTo(x + width, y + height - radius);
this.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
this.lineTo(x + radius, y + height);
this.quadraticCurveTo(x, y + height, x, y + height - radius);
this.lineTo(x, y + radius);
this.quadraticCurveTo(x, y, x + radius, y);
this.closePath();
if(stroke){
context.stroke();
}
}
context.drawDescriptionArea(70, 400, 120, 70);
context.font = '25pt Calibri';
context.strokeText('Asset', 90, 440);
context.drawDescriptionArea(300, 400, 120, 70);
context.strokeText('Liability', 310, 440);
context.drawDescriptionArea(540, 400, 120, 70);
context.strokeText('Income', 550, 440);
context.drawDescriptionArea(750, 400, 180, 70);
context.strokeText('Expenditure', 760, 440);
/*Now draw the images to the canvas */
/*First, create variables for the x & y coordinates of the image that will be drawn.
the x & y coordinates should hold random numbers, so that the images will be
drawn in random locations on the canvas.*/
var imageX = Math.floor(Math.random()*100);
var imageY = Math.floor(Math.random()*100);
/*Create a 'table' of positions that the images will be drawn to */
var imagePositionsX = [20, 80, 140, 200, 260, 320, 380, 440, 500, 560];
var imagePositionsY = [20, 60, 100, 140, 180, 220, 260, 300, 340, 380];
/*Draw all images from assetsImageArray */
/*Use a while loop to loop through the array, get each item and draw it. */
var arrayIteration = 0;
console.log('All Images Array length: ' + allImagesArray.length); /*Display the length of the array in the console, to check it's holding the correct number of images. */
while(arrayIteration < allImagesArray.length){
var randomPositionX = Math.floor(Math.random()*10);
var randomPositionY = Math.floor(Math.random()*10);
context.drawImage(allImagesArray[arrayIteration], imageX, imageY, 50, 50);
console.log(arrayIteration); /*Display the current array position that's being drawn */
arrayIteration = arrayIteration+1;
/*Now try changing the values of imageX & imageY so that the next image is drawn to a
different location*/
imageX = imagePositionsX[randomPositionX]; /* imageX+(Math.floor(Math.random()*100)); */
imageY = imagePositionsY[randomPositionY]; /* imageY+(Math.floor(Math.random()*100)); */
}
}
In conclusion to the comments, I can answer you this: Somewhere within your code, you have to call the canvasState() function, it's not enough just to define it. Where you must call it largely depends on when you need it's functionality. By example, if you want to set up the drag and drop functionality when the page loads, you have an event handler for the body's load event:
<body onLoad="startGame()">
Somewhere in the startGame() function's code, you would call canvasState(). If you you want it when StartButton is pressed, you should call it from within the drawLevelOneElements() function. Since you were following a tutorial, the order in which things happen might matter, so there might be a particular place where you need to call your function.
One more advice. Because you seem to be learning, start with the basics and work your way up with a deep understanding of what you learned up to that point, don't just follow random tutorials.
I am trying to build a floorplan model in Canvas. Currently I have a grid image in my canvas and have the ability for users to draw lines by clicking and dragging their mouse. But, this doesn't guarantee straight lines.
Is there anyway I can provide input fields in the html page for users to input the beginning and ending x and y coordinates of the lines, and have it updated in my canvas code? I'm a beginner when it comes to JS/AJAX, so any remedial help is appreciated :)
Right now, this is the section that dictates how the lines get drawn:
$(document).ready(function() {
var canvas = document.getElementById('canvas');
var context = canvas.getContext("2d");
if(canvas.getContext) {
$('#canvas').mousedown(function (evt) {
var offset = $('#canvas').offset();
context.beginPath();
context.moveTo(20, 20);
});
$(document).mousemove(function(evt) {
var offset = $('#canvas').offset();
context.lineTo(evt.pageX - offset.left, evt.pageY - offset.top);
context.stroke();
}).mouseup(function() {
$(document).unbind('mousemove');
$(document).unbind('mouseup');
});
$('#clearcanvas').click(function () {
context.clearRect(0, 0, 600, 580);
});
}
});
I suspect it involves modifying following code:
context.lineTo(evt.pageX - offset.left, evt.pageY - offset.top);
Very simply you could use 4 input fields and take the value of each when a button is pressed
button.addEventListener('click', function() {
ctx.beginPath();
ctx.moveTo(x1.value, y1.value);
ctx.lineTo(x2.value, y2.value);
ctx.stroke();
}, false);
http://jsfiddle.net/TeGGx/