Related
I need help with a pretty difficult problem. I am currently making a game with React and Redux. In this game I use a canvas to create a map data from my redux store. Currently the map is just a matrix of black and white squares. Let's say that I wanted to change the color of a square when you click on it, but also maintain the ability to drag the element. The problem is that it is difficult to pinpoint exactly where the mouse is clicking given that the element can be dragged anywhere on the page. As far as I can tell, none of the mouseclick event object properties seem to be able to tell me. I thought offsetX and offsetY would tell me, but they don't seem to stay the same when the canvas object moves for some reason.
I am using React and Redux for this project, and the CanvasMap element is wrapped in a Draggable from this library: https://www.npmjs.com/package/react-draggable#draggablecore
import React from 'react'
import { connect } from 'react-redux'
import './CanvasMap.css'
class CanvasMap extends React.Component{
componentDidMount() {
const map = this.props.map //Data representing the map
const canvas = this.refs.canvas
const context = canvas.getContext('2d')
//Building the map on the canvas
for(let i = 0; i < map.length; i++){
for(let j = 0; j < map[i].length; j++){
const x=i*100
const y=j*100
const isBlackSquare= map[i][j] === 'black' ? true : false
if(isBlackSquare) context.fillRect(x, y, 100, 100)
else context.strokeRect(x, y, 100, 100)
}
}
function handleClick(e){
//None of the event properties seem to stay the same when the canvas is moved
console.log(e)
}
canvas.addEventListener('click', handleClick)
}
render(){
return (
<div className='Map'>
<canvas ref='canvas' width={8000} height={8000} />
</div>
)
}
}
function mapStateToProps(state){
return {
map: [...state.map]
}
}
const connectedComponent = connect(mapStateToProps)(CanvasMap)
export { connectedComponent as CanvasMap }
In most cases when you click on an HTML element you can use the rectangleBounding Box and get coordinators from that like
domRect = element.getBoundingClientRect();
in a canvas click position it is a little more difficult
Here is a script I did a while ago to draw while dragging the mouse the on the canvas .Maybe you can apply this method
<html>
<head>
<style>
* { margin:0; padding:0; } /* to remove the top and left whitespace */
html, body { width:100%; height:100%; } /* just to be sure these are full screen*/
canvas { display:block; } /* To remove the scrollbars */
</style>
</head>
<body>
<canvas id="canvas" ></canvas>
<script>
////////////////////////////////////////
(function() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var elemLeft = canvas.offsetLeft;
var elemTop = canvas.offsetTop;
var BB=canvas.getBoundingClientRect();
var offsetX=BB.left;
var offsetY=BB.top;
// resize the canvas to fill browser window dynamically
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
/**
* Your drawings need to be inside this function otherwise they will be reset when
* you resize the browser window and the canvas goes will be cleared.
*/
drawStuff();
}
resizeCanvas();
function drawStuff() {
// do your drawing stuff here
var img = new Image();
img.src = 'images/3PkBe.gif';
img.onload = function()
{
//var canvas = document.getElementById('canvas');
// create pattern
var ptrn = ctx.createPattern(img, 'repeat'); // Create a pattern with this image, and set it to "repeat".
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, canvas.width, canvas.height); // context.fillRect(x, y, width, height);
ctx.shadowBlur=20;
//ctx.shadowColor="black";
//ctx.fillStyle="green";
//ctx.fillRect(20,160,100,80);
ctx.strokeStyle = "lightgray";
//var canvasOffset = canvas.offset();
//var offsetX = canvasOffset.left;
//var offsetY = canvasOffset.top;
var mouseIsDown = false;
var lastX = 0;
var lastY = 0;
var elements = [];
makeShip( 30 , 30,120, 120, '#119' , "romea");
makeShip( 30, 160,120, 120, '#393', "fomar");
makeShip( 30, 290,120, 120, '#955', "ojab");
makeShip( 30, 420,120, 120, '#6ff', "eliot");
// Add event listener for `click` events.
canvas.addEventListener('click', function(event) {
var x = event.pageX - elemLeft,
y = event.pageY - elemTop;
console.info(x, y);
elements.forEach(function(element) {
if (y > element.y && y < element.y + element.height && x > element.x && x < element.x + element.width) {
console.log(element.name);
}
});
}, false);
canvas.addEventListener('mousedown', function(event) {
var x = event.pageX - elemLeft,
y = event.pageY - elemTop;
console.info(x, y);
elements.forEach(function(element) {
if (y > element.y && y < element.y + element.height && x > element.x && x < element.x + element.width) {
console.info(element.name);
handleMouseDown(element);
}
});
}, false);
canvas.addEventListener('mousemove', function(event) {
var x = event.pageX - elemLeft,
y = event.pageY - elemTop;
console.info(x, y);
elements.forEach(function(element) {
if (y > element.y && y < element.y + element.height && x > element.x && x < element.x + element.width) {
console.info(element.name);
handleMouseMove(element,x,y);
}
});
}, false);
canvas.addEventListener('mouseup', function(event) {
var x = event.pageX - elemLeft,
y = event.pageY - elemTop;
//console.info(x, y);
elements.forEach(function(element) {
//if (y > element.y && y < element.y + element.height && x > element.x && x < element.x + element.width) {
console.info(element.name + "mouse up evenr=========");
handleMouseUp(element);
//}
});
}, false);
function makeShip(x, y, width, height, colour,ShipName) {
var ship = {
name: ShipName,
colour: colour,
width: width,
height: height,
x: x,
y: y
}
elements.push(ship);
return (ship);
}
function drawShip(ship) {
//ctx.fillStyle = ship.colour;
//ctx.fillRect(ship.x, ship.y, ship.width, ship.height);
//ctx.fillRect(element.x, element.y, element.width, element.height);
}
function drawAllShips() {
// ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < elements.length; i++) {
var ship = elements[i]
//drawShip(ship);
ctx.fillStyle = ship.colour;
ctx.fillRect(ship.x , ship.y, ship.width, ship.height);
// ctx.fillStyle = ship.fill;
// ctx.fill();
// ctx.stroke();
}
}
// Add element.
//elements.push({
//colour: '#05EFFF',
//width: 150,
//height: 100,
//x: 20,
//y: 15
//});
// Render elements.
// elements.forEach(function(element) {
// ctx.fillStyle = element.colour;
// ctx.fillRect(element.x, element.y, element.width, element.height);
// });
drawAllShips();
function handleMouseDown(e) {
mouseX = e.x ;
mouseY = e.y ;
//mouseX = parseInt(e.x - offsetX);
//mouseY = parseInt(e.y - offsetY);
console.log("===========Problem "+mouseX);
// mousedown stuff here
lastX = mouseX;
lastY = mouseY;
mouseIsDown = true;
//alert("mouse Handle");
}
function handleMouseUp(e) {
//mouseX = parseInt(e.clientX - offsetX);
//mouseY = parseInt(e.clientY - offsetY);
ctx.onmousemove = null;
// mouseup stuff here
mouseIsDown = false;
return
}
function handleMouseMove(e,x,y) {
if (mouseIsDown) {
//console.log(' no fuck');
mouseX = e.x ;
mouseY = e.y ;
console.log(e.name+"is truing to drag");
// mousemove stuff here
//for (var i = 0; i < elements.length; i++) {
//if (ctx.isPointInPath(mouseX, mouseY)) {
//console.log('============== no fuck');
var ship =e;// elements[i];
ship.x = x-15;//(mouseX - lastX);
ship.y = y-20;//(mouseY -lastY);
// ship.right = ship.x + ship.width;
// ship.bottom = ship.y + ship.height;
//drawShip(ship);
//}
//}
lastX = mouseX;
lastY = mouseY;
drawAllShips();
}
}
<!-- ctx.mousedown(function (e) { -->
<!-- handleMouseDown(e); -->
<!-- }); -->
<!-- ctx.mousemove(function (e) { -->
<!-- handleMouseMove(e); -->
<!-- }); -->
<!-- ctx.mouseup(function (e) { -->
<!-- handleMouseUp(e); -->
<!-- }); -->
}
}
})();
</script>
</body>
</html>
SOLVED IT!
I got lost in the slew of data around elements and click events, I was trying to figure out the right combination of pageX, clientX, offsetLeft, screenX, etc. However, the final solution is incredibly simple once you know exactly what to do. Here it is:
function handleClick(e){
const rect = e.target.getBoundingClientRect()
const x = e.pageX - rect.left
const y = e.pageY - rect.top
}
This should get you the exact x and y coordinate of your mouse in relation to the element, no matter where you drag and reposition the element.
function Shape(x, y, w, h, fill) {
this.x = x || 0;
this.y = y || 0;
this.w = w || 1;
this.h = h || 1;
this.fill = fill || '#AAAAAA';
}
Shape.prototype.draw = function(ctx) {
ctx.fillStyle = this.fill;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
Shape.prototype.contains = function(mx, my) {
return (this.x <= mx) && (this.x + this.w >= mx) &&
(this.y <= my) && (this.y + this.h >= my);
}
function CanvasState(canvas) {
this.canvas = canvas;
this.width = canvas.width;
this.height = canvas.height;
this.ctx = canvas.getContext('2d');
var stylePaddingLeft, stylePaddingTop, styleBorderLeft, styleBorderTop;
if (document.defaultView && document.defaultView.getComputedStyle) {
this.stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingLeft'], 10) || 0;
this.stylePaddingTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingTop'], 10) || 0;
this.styleBorderLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderLeftWidth'], 10) || 0;
this.styleBorderTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderTopWidth'], 10) || 0;
}
var html = document.body.parentNode;
this.htmlTop = html.offsetTop;
this.htmlLeft = html.offsetLeft;
this.valid = false;
this.shapes = [];
this.dragging = false;
this.selection = null;
this.dragoffx = 0;
this.dragoffy = 0;
var myState = this;
canvas.addEventListener('selectstart', function(e) { e.preventDefault(); return false; }, false);
canvas.addEventListener('mousedown', function(e) {
var mouse = myState.getMouse(e);
var mx = mouse.x;
var my = mouse.y;
var shapes = myState.shapes;
var l = shapes.length;
for (var i = l-1; i >= 0; i--) {
if (shapes[i].contains(mx, my)) {
var mySel = shapes[i];
myState.dragoffx = mx - mySel.x;
myState.dragoffy = my - mySel.y;
myState.dragging = true;
myState.selection = mySel;
myState.valid = false;
return;
}
}
if (myState.selection) {
myState.selection = null;
myState.valid = false;
}
}, true);
canvas.addEventListener('mousemove', function(e) {
if (myState.dragging){
var mouse = myState.getMouse(e);
myState.selection.x = mouse.x - myState.dragoffx;
myState.selection.y = mouse.y - myState.dragoffy;
myState.valid = false;
}
}, true);
canvas.addEventListener('mouseup', function(e) {
myState.dragging = false;
}, true);
canvas.addEventListener('dblclick', function(e) {
var mouse = myState.getMouse(e);
myState.addShape(new Shape(mouse.x - 10, mouse.y - 10, 20, 20, 'rgba(0,255,0,.6)'));
}, true);
this.selectionColor = '#CC0000';
this.selectionWidth = 2;
this.interval = 30;
setInterval(function() { myState.draw(); }, myState.interval);
}
CanvasState.prototype.addShape = function(shape) {
this.shapes.push(shape);
this.valid = false;
}
CanvasState.prototype.clear = function() {
this.ctx.clearRect(0, 0, this.width, this.height);
}
CanvasState.prototype.draw = function() {
if (!this.valid) {
var ctx = this.ctx;
var shapes = this.shapes;
this.clear();
var l = shapes.length;
for (var i = 0; i < l; i++) {
var shape = shapes[i];
if (shape.x > this.width || shape.y > this.height ||
shape.x + shape.w < 0 || shape.y + shape.h < 0) continue;
shapes[i].draw(ctx);
}
if (this.selection != null) {
ctx.strokeStyle = this.selectionColor;
ctx.lineWidth = this.selectionWidth;
var mySel = this.selection;
ctx.strokeRect(mySel.x,mySel.y,mySel.w,mySel.h);
}
this.valid = true;
}
}
CanvasState.prototype.getMouse = function(e) {
var element = this.canvas, offsetX = 0, offsetY = 0, mx, my;
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
offsetX += this.stylePaddingLeft + this.styleBorderLeft + this.htmlLeft;
offsetY += this.stylePaddingTop + this.styleBorderTop + this.htmlTop;
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
return {x: mx, y: my};
}
function init() {
var s = new CanvasState(document.getElementById('canvas1'));
s.addShape(new Shape(40,40,50,50)); // The default is gray
}
<canvas id="canvas1" width="200" height="200" style="border:1px solid #000000;">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
<button onclick= "init()">click </button>
On click of a button, I am creating a rectangular element which can be drag and drop inside the canvas element restricted area.
however, Is it possible to create a new rectangular element dynamically on every click of a button which can further be drag and drop inside the canvas boundary.
And the previous rectangular element won't lost.
Doing this from scratch will be a lot of work. I suggest you use a library like fabric.js which has everything you asked plus a lot more to offer. Here is a demo page.
On every button click you was calling init(),.. Causing you CanvasState to reset.
I've just made another function called addShape, and just called init once.
I've also kept a reference to the CanvasState, called s.. So I could do s.addShape.. So changes were very minimal.
Hope this helps..
function Shape(x, y, w, h, fill) {
this.x = x || 0;
this.y = y || 0;
this.w = w || 1;
this.h = h || 1;
this.fill = fill || '#AAAAAA';
}
Shape.prototype.draw = function(ctx) {
ctx.fillStyle = this.fill;
ctx.fillRect(this.x, this.y, this.w, this.h);
}
Shape.prototype.contains = function(mx, my) {
return (this.x <= mx) && (this.x + this.w >= mx) &&
(this.y <= my) && (this.y + this.h >= my);
}
function CanvasState(canvas) {
this.canvas = canvas;
this.width = canvas.width;
this.height = canvas.height;
this.ctx = canvas.getContext('2d');
var stylePaddingLeft, stylePaddingTop, styleBorderLeft, styleBorderTop;
if (document.defaultView && document.defaultView.getComputedStyle) {
this.stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingLeft'], 10) || 0;
this.stylePaddingTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingTop'], 10) || 0;
this.styleBorderLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderLeftWidth'], 10) || 0;
this.styleBorderTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderTopWidth'], 10) || 0;
}
var html = document.body.parentNode;
this.htmlTop = html.offsetTop;
this.htmlLeft = html.offsetLeft;
this.valid = false;
this.shapes = [];
this.dragging = false;
this.selection = null;
this.dragoffx = 0;
this.dragoffy = 0;
var myState = this;
canvas.addEventListener('selectstart', function(e) { e.preventDefault(); return false; }, false);
canvas.addEventListener('mousedown', function(e) {
var mouse = myState.getMouse(e);
var mx = mouse.x;
var my = mouse.y;
var shapes = myState.shapes;
var l = shapes.length;
for (var i = l-1; i >= 0; i--) {
if (shapes[i].contains(mx, my)) {
var mySel = shapes[i];
myState.dragoffx = mx - mySel.x;
myState.dragoffy = my - mySel.y;
myState.dragging = true;
myState.selection = mySel;
myState.valid = false;
return;
}
}
if (myState.selection) {
myState.selection = null;
myState.valid = false;
}
}, true);
canvas.addEventListener('mousemove', function(e) {
if (myState.dragging){
var mouse = myState.getMouse(e);
myState.selection.x = mouse.x - myState.dragoffx;
myState.selection.y = mouse.y - myState.dragoffy;
myState.valid = false;
}
}, true);
canvas.addEventListener('mouseup', function(e) {
myState.dragging = false;
}, true);
canvas.addEventListener('dblclick', function(e) {
var mouse = myState.getMouse(e);
myState.addShape(new Shape(mouse.x - 10, mouse.y - 10, 20, 20, 'rgba(0,255,0,.6)'));
}, true);
this.selectionColor = '#CC0000';
this.selectionWidth = 2;
this.interval = 30;
setInterval(function() { myState.draw(); }, myState.interval);
}
CanvasState.prototype.addShape = function(shape) {
this.shapes.push(shape);
this.valid = false;
}
CanvasState.prototype.clear = function() {
this.ctx.clearRect(0, 0, this.width, this.height);
}
CanvasState.prototype.draw = function() {
if (!this.valid) {
var ctx = this.ctx;
var shapes = this.shapes;
this.clear();
var l = shapes.length;
for (var i = 0; i < l; i++) {
var shape = shapes[i];
if (shape.x > this.width || shape.y > this.height ||
shape.x + shape.w < 0 || shape.y + shape.h < 0) continue;
shapes[i].draw(ctx);
}
if (this.selection != null) {
ctx.strokeStyle = this.selectionColor;
ctx.lineWidth = this.selectionWidth;
var mySel = this.selection;
ctx.strokeRect(mySel.x,mySel.y,mySel.w,mySel.h);
}
this.valid = true;
}
}
CanvasState.prototype.getMouse = function(e) {
var element = this.canvas, offsetX = 0, offsetY = 0, mx, my;
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
offsetX += this.stylePaddingLeft + this.styleBorderLeft + this.htmlLeft;
offsetY += this.stylePaddingTop + this.styleBorderTop + this.htmlTop;
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
return {x: mx, y: my};
}
var s;
function init() {
s = new CanvasState(document.getElementById('canvas1'));
}
function addShape() {
s.addShape(new Shape(40,40,50,50)); // The default is gray
}
init();
<canvas id="canvas1" width="400" height="300" style="border:1px solid #000000;">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
<button onclick= "addShape()">click </button>
(english is not my native language, hope you cope on this)
I'm having trouble why is my text can't be dragged when I add another canvas on it.
Basically, what I wanted to happen is I can drag my text and draw, and when I click the button "DRAW" i will start to draw.
Here's my code :
// FUNCTION FOR DRAWING !!!
$(function() {
$.each(['#f00', '#ff0', '#0f0'], function() {
$('#colors_demo').append("<a href='#colors_sketch' data-color='" + this + "' style='width: 30px;height: 30px;display:inline-block; background: " + this + ";'></a> ");
});
$('#colors_sketch').sketch();
$('#colors_sketch').sketch({defaultColor: "#ff0"});
});
//FUNCTION FOR DISPLAY TEXT!!!
function cakeDedicationFree() {
if (document.getElementById('design3').checked) {
var canvas2 = document.getElementById("colors_sketch");
context = canvas2.getContext("2d");
var $canvas2 = $("#colors_sketch");
var canvasOffset = $canvas2.offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var scrollX = $canvas2.scrollLeft();
var scrollY = $canvas2.scrollTop();
var startX;
var startY;
var texts = []; // an array to hold text objects
var selectedText = -1;// this var will hold the index of the hit-selected text
function draw()
{ // clear the canvas & redraw all texts
context.clearRect(0, 0, canvas2.width, canvas2.height);
for (var i = 0; i < texts.length; i++)
{
var text = texts[i];
context.fillText(text.text, text.x, text.y);
}
}
function textHittest(x, y, textIndex) { // test if x,y is inside the bounding box of texts[textIndex]
var text = texts[textIndex];
return (x >= text.x && x <= text.x + text.width && y >= text.y - text.height && y <= text.y);
}
function handleMouseDown(d) {
d.preventDefault();
startX = parseInt(d.clientX - offsetX);
startY = parseInt(d.clientY - offsetY);
for (var i = 0; i < texts.length; i++) {
if (textHittest(startX, startY, i)) {
selectedText = i; } }
}
function handleMouseUp(d) { // done dragging
d.preventDefault();
selectedText = -1; }
function handleMouseOut(d) { // also done dragging
d.preventDefault();
selectedText = -1; }
function handleMouseMove(d) {
if (selectedText < 0) { return; }
d.preventDefault();
mouseX = parseInt(d.clientX - offsetX);
mouseY = parseInt(d.clientY - offsetY);
var dx = mouseX - startX;
var dy = mouseY - startY;
startX = mouseX;
startY = mouseY;
var text = texts[selectedText];
text.x += dx;
text.y += dy;
draw(); }
$("#colors_sketch").mousedown(function (d) { handleMouseDown(d); }); // listen for mouse events
$("#colors_sketch").mousemove(function (d) { handleMouseMove(d); });
$("#colors_sketch").mouseup(function (d) { handleMouseUp(d); });
$("#colors_sketch").mouseout(function (d) { handleMouseOut(d); });
$("#text_dedi").click(function () {
var y = texts.length * 20 + 20;
var text = { text: $("#dedi_text").val(),
x: 20,
y: y
};
context.font = "30px Roboto";
text.width = context.measureText(text.text).width;
text.height = 16;
text.color = "#fff";
texts.push(text); // put this new text in the texts array
draw(); // redraw everything
});
document.getElementById('clear').addEventListener('click', function() {
context.clearRect(0, 0, canvas2.width, canvas2.height);
texts = []; },
false);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://intridea.github.io/sketch.js/lib/sketch.js"></script>
<!-- DRAWING PART -->
<div id="colors_demo" class="tools">
</div>
<div class="tools">
Marker
Eraser
</div>
<!-- DISPLAY TEXT PART -->
<br> <input type="radio" id="design3" name="design_3" onchange="cakeDedicationFree()" />
Text
<input type="text" size="15" id="dedi_text" name="dedicationT" placeholder="Text">
<button id="text_dedi"> Post </button> <input type="button" value="Clear" id="clear" size="23" >
<canvas id="colors_sketch" width="800" height="300"></canvas>
AS you can see, there's a big bug happening ..
worst part in my system it really doesn't show up.
Hope someone can help me.. Thank you in advance!!!
I have this [sample][1], what I want is to have this result[![enter image description here][2]][2]
Note:
a.) 1 and 2 will be connected while 3 will be produced in the third mousedown click.
b.) 1,2,3 should be declared continously.
c.) 1 and 2 can be extend for the width
d.) 3 should be extend for the height.
e.) 1,2,3 should be drag as a whole (all together).
f.) The pattern of declaration is 1 to 2 (horizontally) and 2 to 3 (vertical).
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
draggingIndex=-1;
for(var i=0;i<anchors.length;i++){
var a=anchors[i];
var dx=startX-a.x;
var dy=startY-a.y;
if(dx*dx+dy*dy<radius*radius){
draggingIndex=i;
break;
}
}
//Detect if we're on a line:
fullDrag = mouseOnLine({x:startX, y: startY});
// If a drag hasn't started, add another anchor here
if(draggingIndex==-1 && fullDrag == null){
addAnchor(startX,startY);
var al = anchors.length-1;
var almod4 = al%2;
if(almod4==1){
connectors.push({start:al-1,end:al});
}
if(almod4==2){
connectors.push({start:al-2,end:al});
connectors.push({start:al-1,end:al});
}
draw();
}
}
I think, you can use the slope with the actual mouse point. The delta is only used by half.
deltaX = (anchors[al - 1].x - anchors[al].x) / 2;
deltaY = (anchors[al - 1].y - anchors[al].y) / 2;
ctx.strokeStyle = 'purple';
ctx.beginPath();
ctx.moveTo(mouseX - deltaX, mouseY - deltaY);
ctx.lineTo(mouseX + deltaX, mouseY + deltaY);
ctx.stroke();
Working example:
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
cw = canvas.width,
ch = canvas.height,
mouseX, mouseY,
offsetX, offsetY,
startX, startY,
radius = 5,
nextLetter = 0,
anchors = [],
connectors = [],
draggingIndex = -1,
fullDrag = null;
reOffset();
window.onscroll = function (e) { reOffset(); }
window.onresize = function (e) { reOffset(); }
function reOffset() {
var BB = canvas.getBoundingClientRect();
offsetX = BB.left;
offsetY = BB.top;
}
function addAnchor(x, y) {
anchors.push({
x: x,
y: y,
});
}
draw();
$("#canvas").mousedown(function (e) { handleMouseDown(e); });
$("#canvas").mousemove(function (e) { handleMouseMove(e); });
$("#canvas").mouseup(function (e) { handleMouseUpOut(e); });
$("#canvas").mouseout(function (e) { handleMouseUpOut(e); });
$("#clear").click(function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
anchors = [];
connectors = [];
});
function draw() {
var deltaX, deltaY;
var al = anchors.length - 1;
//
ctx.clearRect(0, 0, cw, ch);
ctx.strokeStyle = 'black';
// draw connecting lines
for (var i = 0; i < connectors.length; i++) {
var c = connectors[i];
var s = anchors[c.start];
var e = anchors[c.end];
ctx.beginPath();
ctx.moveTo(s.x, s.y);
ctx.lineTo(e.x, e.y);
ctx.stroke();
//alert(anchors.length);
}
//draw lines
if (anchors.length > 0 && anchors.length % 3 > 0) {
ctx.strokeStyle = 'grey';
var almod4 = al % 2;
if (almod4 == 1 || almod4 == 2) {
//draw extra line
ctx.beginPath();
ctx.moveTo(anchors[al - 1].x, anchors[al - 1].y);
ctx.lineTo(mouseX, mouseY);
ctx.stroke();
// part for parallel line
deltaX = (anchors[al - 1].x - anchors[al].x) / 2;
deltaY = (anchors[al - 1].y - anchors[al].y) / 2;
ctx.strokeStyle = 'purple';
ctx.beginPath();
ctx.moveTo(mouseX - deltaX, mouseY - deltaY);
ctx.lineTo(mouseX + deltaX, mouseY + deltaY);
ctx.stroke();
}
ctx.strokeStyle = 'grey';
ctx.beginPath();
ctx.moveTo(anchors[al].x, anchors[al].y);
ctx.lineTo(mouseX, mouseY);
ctx.stroke();
}
// draw circles
for (var i = 0; i < anchors.length; i++) {
ctx.beginPath();
ctx.arc(anchors[i].x, anchors[i].y, radius, 0, Math.PI * 2);
ctx.fill();
}
}
function handleMouseDown(e) {
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
draggingIndex = -1;
for (var i = 0; i < anchors.length; i++) {
var a = anchors[i];
var dx = startX - a.x;
var dy = startY - a.y;
if (dx * dx + dy * dy < radius * radius) {
draggingIndex = i;
break;
}
}
//Detect if we're on a line:
fullDrag = mouseOnLine({ x: startX, y: startY });
// If a drag hasn't started, add another anchor here
if (draggingIndex == -1 && fullDrag == null) {
addAnchor(startX, startY);
var al = anchors.length - 1;
var almod4 = al % 2;
if (almod4 == 1) {
connectors.push({ start: al - 1, end: al });
}
if (almod4 == 2) {
connectors.push({ start: al - 2, end: al });
connectors.push({ start: al - 1, end: al });
}
draw();
}
}
function handleMouseUpOut(e) {
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
draggingIndex = -1;
fullDrag = null;
}
function handleMouseMove(e) {
//if(draggingIndex<0 && fullDrag == null){return;}
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
if (draggingIndex >= 0) {
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
var a = anchors[draggingIndex];
a.x += (mouseX - startX);
a.y += (mouseY - startY);
startX = mouseX;
startY = mouseY;
} else if (fullDrag != null) {
var startPoints = Math.floor(fullDrag.start / 4) * 4;
for (var i = 0; i < 2; i++) {
anchors[startPoints + i].x += (mouseX - startX);
anchors[startPoints + i].y += (mouseY - startY);
}
startX = mouseX;
startY = mouseY;
}
draw();
}
function mouseOnLine(mousePos) {
var i, pA, pB, first, second;
for (i = 0 ; i < connectors.length; i++) {
pA = anchors[connectors[i].start];
pB = anchors[connectors[i].end];
first = distanceBetween(pA, mousePos) + distanceBetween(pB, mousePos);
second = distanceBetween(pA, pB);
if (Math.abs(first - second) < 0.3) {
return connectors[i];
}
}
return null;
}
var distanceBetween = function (point1, point2) {
var distX = Math.abs(point1.x - point2.x);
var distY = Math.abs(point1.y - point2.y);
return Math.sqrt((distX * distX) + (distY * distY));
}
#canvas{border:1px solid red; }
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<canvas id="canvas" width=500 height=500></canvas>
I am using jsfiddle to store some coordinates. The coordinates gets displayed on jsfiddle but when I copy it on my local files the coordinates don't get displayed.
I would like to display the coordinates of that line on my local files, How can this be done?
This is my HTML file
<canvas id="canvas" width="300" height="300" style="border: 1px solid black;"> </canvas>
<div id="coord"></div>
<div id="coords"></div>
This is my Javascript File
var canvas = document.getElementById('canvas'),
coord = document.getElementById('coord'),
ctx = canvas.getContext('2d'), // get 2D context
imgCat = new Image(),
arr = [];
imgCat.src = ''http://c.wearehugh.com/dih5/openclipart.org_media_files_johnny_automatic_1360.png';
imgCat.onload = function() { // wait for image load
ctx.drawImage(imgCat, 0, 0); // draw imgCat on (0, 0)
};
var mousedown = false;
ctx.strokeStyle = '#0000FF';
ctx.lineWidth = 5;
canvas.onmousedown = function(e) {
arr = [];
var pos = fixPosition(e, canvas);
mousedown = true;
ctx.beginPath();
ctx.moveTo(pos.x, pos.y);
return false;
};
canvas.onmousemove = function(e) {
var pos = fixPosition(e, canvas);
coord.innerHTML = '(' + pos.x + ',' + pos.y + ')';
if (mousedown) {
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
arr.push([pos.x, pos.y])
}
};
canvas.onmouseup = function(e) {
mousedown = false;
$('#coords').html(JSON.stringify(arr, null, 2));
};
function fixPosition(e, gCanvasElement) {
var x;
var y;
if (e.pageX || e.pageY) {
x = e.pageX;
y = e.pageY;
}
else {
x = e.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
y = e.clientY + document.body.scrollTop +
document.documentElement.scrollTop;
}
x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;
return {x: x, y:y};
}
Demo Here
Copy this in a html page. The probleme was your link imgCat.src = ''http://c.wearehugh.com/dih5/openclipart.org_media_files_johnny_automatic_1360.png';
You put two ''
<html>
<canvas id="canvas" width="300" height="300" style="border: 1px solid black;"></canvas>
<div id="coord"></div>
<div id="coords"></div>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.1.min.js</script>
</html>
<script type="text/javascript">
var canvas = document.getElementById('canvas'),
coord = document.getElementById('coord'),
ctx = canvas.getContext('2d'), // get 2D context
imgCat = new Image(),
arr = [];
imgCat.src ='http://www.clipartbest.com/cliparts/bTy/E5x/bTyE5xLjc.png';
imgCat.onload = function() { // wait for image load
ctx.drawImage(imgCat, 0, 0); // draw imgCat on (0, 0)
};
var mousedown = false;
ctx.strokeStyle = '#0000FF';
ctx.lineWidth = 5;
canvas.onmousedown = function(e) {
arr = [];
var pos = fixPosition(e, canvas);
mousedown = true;
ctx.beginPath();
ctx.moveTo(pos.x, pos.y);
return false;
};
canvas.onmousemove = function(e) {
var pos = fixPosition(e, canvas);
coord.innerHTML = '(' + pos.x + ',' + pos.y + ')';
if (mousedown) {
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
arr.push([pos.x, pos.y])
}
};
canvas.onmouseup = function(e) {
mousedown = false;
$('#coords').html(JSON.stringify(arr, null, 2));
};
function fixPosition(e, gCanvasElement) {
var x;
var y;
if (e.pageX || e.pageY) {
x = e.pageX;
y = e.pageY;
}
else {
x = e.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
y = e.clientY + document.body.scrollTop +
document.documentElement.scrollTop;
}
x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;
return {x: x, y:y};
}
</script>
some configuration is applying to jsfiddle automatically and you need to apply them by your hands.
first you need to add jQuery to you site. Add this line between <head> </head> tags:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
second you need to check that you script executes for example when page loads. you need to put you code into this:
$(function() {
// You script here
});
or put it just before </body> tag
so in output you jquery code will be like this:
<script>
$(function() {
var canvas = document.getElementById('canvas'),
coord = document.getElementById('coord'),
ctx = canvas.getContext('2d'), // get 2D context
imgCat = new Image(),
arr = [];
imgCat.src = ''http://c.wearehugh.com/dih5/openclipart.org_media_files_johnny_automatic_1360.png';
imgCat.onload = function() { // wait for image load
ctx.drawImage(imgCat, 0, 0); // draw imgCat on (0, 0)
};
var mousedown = false;
ctx.strokeStyle = '#0000FF';
ctx.lineWidth = 5;
canvas.onmousedown = function(e) {
arr = [];
var pos = fixPosition(e, canvas);
mousedown = true;
ctx.beginPath();
ctx.moveTo(pos.x, pos.y);
return false;
};
canvas.onmousemove = function(e) {
var pos = fixPosition(e, canvas);
coord.innerHTML = '(' + pos.x + ',' + pos.y + ')';
if (mousedown) {
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
arr.push([pos.x, pos.y])
}
};
canvas.onmouseup = function(e) {
mousedown = false;
$('#coords').html(JSON.stringify(arr, null, 2));
};
function fixPosition(e, gCanvasElement) {
var x;
var y;
if (e.pageX || e.pageY) {
x = e.pageX;
y = e.pageY;
}
else {
x = e.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
y = e.clientY + document.body.scrollTop +
document.documentElement.scrollTop;
}
x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;
return {x: x, y:y};
}
});
</script>
1.Check the doc type of the HTML :should be html for (HTML 5)or no doc type
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2.Make sure your scripts are getting loaded properly.
Check the path of Jquery script.
--Externally downloaded scripts need to be unblocked
(Righ Click -> Properties -> (General Tab)'Unblock' Option on bottom)
(Right Click -> Properties -> (general Tab) -> Advanced -> Uncheck Encrypt option if checked.)
3.Put your code inside a function.
(Specifically the binding related codes.)
Other functions need to be defined outside document ready.(Already done)
And Call that function inside document ready.
$(document).ready(function () {
DrawImage();
});
function DrawImage()
{
//your code here
var canvas = document.getElementById('canvas'),
coord = document.getElementById('coord'),
ctx = canvas.getContext('2d'), // get 2D context
imgCat = new Image(),
arr = [];
/*********** draw image *************/
imgCat.src = 'http://c.wearehugh.com/dih5/openclipart.org_media_files_johnny_automatic_1360.png';
imgCat.onload = function() { // wait for image load
ctx.drawImage(imgCat, 0, 0); // draw imgCat on (0, 0)
};
/*********** handle mouse events on canvas **************/
var mousedown = false;
ctx.strokeStyle = '#0000FF';
ctx.lineWidth = 5;
canvas.onmousedown = function(e) {
arr = [];
var pos = fixPosition(e, canvas);
mousedown = true;
ctx.beginPath();
ctx.moveTo(pos.x, pos.y);
return false;
};
canvas.onmousemove = function(e) {
var pos = fixPosition(e, canvas);
coord.innerHTML = '(' + pos.x + ',' + pos.y + ')';
if (mousedown) {
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
arr.push([pos.x, pos.y])
}
};
canvas.onmouseup = function(e) {
mousedown = false;
$('#coords').html(JSON.stringify(arr, null, 2));
};
}
//Utils
function fixPosition(e, gCanvasElement) {
//put codes of this function here.
}
just add your script before end of body tag and your problem will solve.