I'm trying to draw a circle on canvas on mouse move, but without success. My code is as follows:
var damages_canvas = document.getElementById('damages-area');
var ctx_damages = damages_canvas.getContext('2d');
var circle_rect = damages_canvas.getBoundingClientRect();
var circle_drag = false;
var circle_canvas_update = true;
var circles = [];
var markerColor = "#f00";
damages_canvas.addEventListener('mousedown', drawCircleMouseDown, false);
damages_canvas.addEventListener('mouseup', drawCircleMouseUp, false);
damages_canvas.addEventListener('mousemove', drawCircleMouseMove, false);
requestAnimationFrame(updateCircleCanvas);
function updateCircleCanvas(){
if(circle_canvas_update){
drawCircleCanvas();
circle_canvas_update = false;
}
requestAnimationFrame(updateCircleCanvas);
}
function drawCircle(circle){
var startX = circle.startX,
endX = circle.endX,
startY = circle.startY,
endY = circle.endY;
ctx_damages.clearRect(0,0,damages_canvas.width,damages_canvas.height);
ctx_damages.beginPath();
ctx_damages.moveTo(startX, startY + (endY-startY)/2);
ctx_damages.bezierCurveTo(startX, startY, endX, startY, endX, startY + (endX-startY)/2);
ctx_damages.bezierCurveTo(endX, endY, startX, endY, startX, startY + (endY-startY)/2);
ctx_damages.closePath();
ctx_damages.stroke();
}
function drawCircleCanvas(){
ctx_damages.setTransform(1,0,0,1,0,0);
ctx_damages.clearRect(0, 0, damages_canvas.width, damages_canvas.height);
ctx_damages.fillStyle = "transparent"; // Color
ctx_damages.strokeStyle = markerColor; // Color
circles.forEach(drawCircle)
}
function drawCircleMouseDown(e){
circle = {
startX : e.offsetX - circle_rect.left,
startY : e.offsetY - circle_rect.top,
endX : 10,
endY : 10
};
circle_drag = true;
circles.push(circle);
circle_canvas_update = true;
}
function drawCircleMouseUp(){
circle_drag = false;
circle_canvas_update = true;
}
function drawCircleMouseMove(e){
if(circle_drag){
circle.endX = e.offsetX - circle_rect.left;
circle.endY = e.offsetY - circle_rect.top;
circle_canvas_update = true;
}
}
#damages-area {background:#f9f9f9}
<canvas id="damages-area" width=600 height=600></canvas>
I want to draw a circle, not ellipsis or anything else. But in my case I get something strange.
Here is also the fiddle.
Any idea how can I do it?
Use arc to draw an arc in canvas. For circle start and end angles will be 0 and 2*Math.PI
var damages_canvas = document.getElementById('damages-area');
var ctx_damages = damages_canvas.getContext('2d');
var circles = [];
var markerColor = "#f00";
var offsetX = damages_canvas.offsetLeft;
var offsetY = damages_canvas.offsetTop;
var startX;
var startY;
var isMouseDown = false;
var circle, radius;
damages_canvas.addEventListener('mousedown', drawCircleMouseDown, false);
damages_canvas.addEventListener('mouseup', drawCircleMouseUp, false);
damages_canvas.addEventListener('mousemove', drawCircleMouseMove, false);
function Circle(startX, startY) {
this.startX = startX;
this.startY = startY;
this.radius;
this.draw = function() {
ctx_damages.beginPath();
ctx_damages.arc(this.startX, this.startY, this.radius, 0, 2 * Math.PI);
ctx_damages.strokeStyle = markerColor;
ctx_damages.stroke();
}
}
function drawCircleMouseDown(e) {
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
isMouseDown = true;
circle = new Circle(startX, startY);
circles.push(circle);
}
function drawCircleMouseUp() {
isMouseDown = false;
circle = null;
}
function drawCircleMouseMove(e) {
if (!isMouseDown) {
return;
}
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
circle.radius = getDistance(startX, startY, mouseX, mouseY);
ctx_damages.clearRect(0, 0, damages_canvas.width, damages_canvas.height);
circles.forEach(function(circ) {
circ.draw();
});
}
function getDistance(p1X, p1Y, p2X, p2Y) {
return Math.sqrt(Math.pow(p1X - p2X, 2) + Math.pow(p1Y - p2Y, 2))
}
#damages-area {background:#f9f9f9}
<canvas id="damages-area" width=600 height=600></canvas>
These changes:
var b=0.55191502449;
var damages_canvas = document.getElementById("damages-area");
var ctx_damages = damages_canvas.getContext("2d");
var circle_rect = damages_canvas.getBoundingClientRect();
var circles = [];
var markerColor = "#f00";
var circle_drag = false;
var circle_canvas_update = true;
damages_canvas.addEventListener('mousedown', drawCircleMouseDown, false);
damages_canvas.addEventListener('mouseup', drawCircleMouseUp, false);
damages_canvas.addEventListener('mousemove', drawCircleMouseMove, false);
requestAnimationFrame(updateCircleCanvas);
function updateCircleCanvas(){
if(circle_canvas_update){
drawCircleCanvas();
circle_canvas_update = false;
}
requestAnimationFrame(updateCircleCanvas);
}
function drawCircle(circle){
var k=circle.firstk,siiry= circle.startY,siirx= circle.startX;
ctx_damages.clearRect(0,0,damages_canvas.width,damages_canvas.height);
ctx_damages.beginPath();
ctx_damages.moveTo(0*k+siirx, 1*k+siiry);
ctx_damages.bezierCurveTo(b*k+siirx, 1*k+siiry, 1*k+siirx, b*k+siiry,
1*k+siirx, 0+siiry);
ctx_damages.moveTo(0*k-(2*0*k)+siirx, 1*k-(2*1*k)+siiry);
ctx_damages.bezierCurveTo(b*k-(2*b*k)+siirx, 1*k-(2*1*k)+siiry, 1*k-
(2*1*k)+siirx, b*k-(2*b*k)+siiry, 1*k-(2*1*k)+siirx, 0-(2*0)+siiry);
ctx_damages.moveTo(0*k+siirx, 1*k+siiry);
ctx_damages.bezierCurveTo(b*k-(2*b*k)+siirx, 1*k+siiry, 1*k-(2*1*k)+siirx,
b*k+siiry, 1*k-(2*1*k)+siirx, 0-(2*0)+siiry);
ctx_damages.moveTo(0*k-(2*0*k)+siirx, 1*k-(2*1*k)+siiry);
ctx_damages.bezierCurveTo(b*k+siirx, 1*k-(2*1*k)+siiry, 1*k+siirx, b*k-
(2*b*k)+siiry, 1*k+siirx, 0+siiry);
ctx_damages.stroke();
}
function drawCircleMouseDown(e){
circle = {
startX : e.offsetX - circle_rect.left,
startY : e.offsetY - circle_rect.top,
firstk : 10
};
circle_drag = true;
circles.push(circle);
circle_canvas_update = true;
}
function drawCircleCanvas(){
ctx_damages.setTransform(1,0,0,1,0,0);
ctx_damages.clearRect(0, 0, damages_canvas.width, damages_canvas.height);
ctx_damages.fillStyle = "transparent"; // Color
ctx_damages.strokeStyle = markerColor; // Color
circles.forEach(drawCircle)
}
function drawCircleMouseUp(){
circle_drag = false;
circle_canvas_update = true;
}
function drawCircleMouseMove(e){ // tätä uusi
if(circle_drag){
console.log(e.offsetX -circle.startX );
circle.firstk =Math.hypot((e.offsetX -circle.startX),(e.offsetY -
circle.startY))
circle_canvas_update = true;
}
}
I jsfidle this https://jsfiddle.net/narutofanforewe/u13ujcrL/1/
Check my blog too http://www.thenew3d.website/2018/02/28/bezier-circle/
Related
I should draw a rectangle inside a pdf document in canvas, but it cleans the background of document.
I want a way to draw a rectangle in it without cleaning the background. Please can anyone help me with this.
Below is the code i am using:
$("#div").mouseover(function () {
$("canvas").on('click', function (e) {
console.log(nr)
id = ($(this).attr("id"));
console.log(id)
const baseImage = loadImage("");
var canvas = document.getElementById(id);
var ctx = canvas.getContext('2d');
Canvas = ctx;
var canvasx = $(canvas).offset().left;
var canvasy = $(canvas).offset().top;
var last_mousex = last_mousey = 0;
var prev_x = prev_y = prev_w = prev_h = 0;
var mousex = mousey = 0;
var mousedown = false;
$(canvas).on('mousedown', function (e) {
if (rectanglearray.length < 2) {
last_mousex = parseInt(e.clientX - canvasx);
last_mousey = parseInt(e.clientY - canvasy);
mousedown = true;
}
});
$(canvas).on('mouseup', function (e) {
mousedown = false;
});
$(canvas).on('mousemove', function (e) {
mousex = parseInt(e.clientX - canvasx);
mousey = parseInt(e.clientY - canvasy);
if (mousedown) {
//if (rectanglearray.length < 2) {
ctx.clearRect(0, 0, canvas.width, canvas.height); //clear canvas
ctx.beginPath();
var width = mousex - last_mousex;
var height = mousey - last_mousey;
ctx.rect(last_mousex, last_mousey, width, height);
a = last_mousex;
b = last_mousey;
c = last_mousex + width;
d = last_mousey + height;
gjer = width;
lart = height;
t = a;
h = b;
gjere = gjer;
larte = lart;
nfq = id.substring(3, 4);
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.stroke();
rectanglearray.push(ctx);
//}
}
});
execute++;
});
});
so when i click in one of the pages of pdf it takes pages id and allows to only draw a rectangle in that page, but when i draw it cleans the background.
I want to draw rectangle on canvas. Below code is working fine except when i draw rectangle it does't show path when mouse is moving. When i left the mouse then rectangle is visible on canvas.
Please help,
Thanks
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
currShape = 'rectangle',
mouseIsDown = 0,
startX, endX, startY, endY,
dot_flag = false;
var x = "white",
y = 2;
function init() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
var imageObj = new Image(); //Canvas image Obj
imageObj.onload = function() {
ctx.drawImage(imageObj, 69, 50); //Load Image on canvas
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'; //Load Image
w = canvas.width; // Canvas Width
h = canvas.height; // Canvas Height
//Check Shape to be draw
eventListener();
}
function eventListener(){
if(currShape=='rectangle'){
canvas.addEventListener("mousedown",function (e) {
mouseDown(e);
}, false);
canvas.addEventListener("mousemove",function (e){
mouseXY(e);
}, false);
canvas.addEventListener("mouseup", function (e){
mouseUp(e);
}, false);
}
}
function mouseUp(eve) {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
if(currShape=='rectangle')
{
drawSquare(); //update on mouse-up
}
}
}
function mouseDown(eve) {
mouseIsDown = 1;
var pos = getMousePos(canvas, eve);
startX = endX = pos.x;
startY = endY = pos.y;
if(currShape=='rectangle')
{
drawSquare(); //update on mouse-up
}
}
function mouseXY(eve) {
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
//drawSquare();
}
}
function drawSquare() {
// creating a square
var w = endX - startX;
var h = endY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
ctx.beginPath();
ctx.globalAlpha=0.7;
ctx.rect(startX + offsetX, startY + offsetY, width, height);
ctx.fillStyle = x;
ctx.fill();
ctx.lineWidth = y;
ctx.strokeStyle = x;
ctx.stroke();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
.colortool div {
width: 15px;
height: 15px;
float: left;
margin-left: 2px;
}
.clear {
clear: both;
}
<!DOCTYPE HTML>
<html>
<body onload="init()">
<div class="canvasbody">
<canvas id="can" width="400" height="400" style="border:1px dotted #eee;"></canvas>
</div>
</body>
</html>
Here is you new JavaScript
var canvas, cnvHid, cnvRender, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
currShape = 'rectangle',
mouseIsDown = 0,
startX, endX, startY, endY,
dot_flag = false;
var x = "white",
y = 2;
function init() {
canvas = document.getElementById('can');
cnvHid = document.getElementById( "canHid" );
cnvRender = document.getElementById( "canRend" );
ctx = canvas.getContext("2d");
var imageObj = new Image(); //Canvas image Obj
imageObj.onload = function() {
ctx.drawImage(imageObj, 69, 50); //Load Image on canvas
renderAllCanvas();
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'; //Load Image
w = canvas.width; // Canvas Width
h = canvas.height; // Canvas Height
//Check Shape to be draw
eventListener();
}
function eventListener(){
if(currShape=='rectangle'){
cnvRender.addEventListener("mousedown",function (e) {
mouseDown(e);
renderAllCanvas();
}, false);
cnvRender.addEventListener("mousemove",function (e){
mouseXY(e);
renderAllCanvas();
}, false);
cnvRender.addEventListener("mouseup", function (e){
mouseUp(e);
renderAllCanvas();
}, false);
}
}
function mouseUp(eve) {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
if(currShape=='rectangle')
{
drawSquare( canvas ); //update on mouse-up
cnvHid.getContext( "2d" ).clearRect( 0, 0, cnvHid.width, cnvHid.height );
}
}
}
function mouseDown(eve) {
mouseIsDown = 1;
var pos = getMousePos(canvas, eve);
startX = endX = pos.x;
startY = endY = pos.y;
if(currShape=='rectangle')
{
drawSquare( canvas ); //update on mouse-up
}
}
function mouseXY(eve) {
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
drawSquare( cnvHid, true );
}
}
function drawSquare( cnv, clear ) {
var ctx = cnv.getContext( "2d" );
if( clear && clear === true ){
ctx.clearRect( 0, 0, cnv.width, cnv.height );
}
// creating a square
var w = endX - startX;
var h = endY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
ctx.beginPath();
ctx.globalAlpha=0.7;
ctx.rect(startX + offsetX, startY + offsetY, width, height);
ctx.fillStyle = x;
ctx.fill();
ctx.lineWidth = y;
ctx.strokeStyle = x;
ctx.stroke();
ctx.closePath();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
function renderAllCanvas(){
var cnxRender = cnvRender.getContext( "2d" );
cnxRender.drawImage(
canvas
,0,0
,cnvRender.width,cnvRender.height
);
cnxRender.drawImage(
cnvHid
,0,0
,cnvRender.width,cnvRender.height
);
}
And here is you new HTML
<!DOCTYPE HTML>
<html>
<body onload="init()">
<div class="canvasbody">
<canvas id="can" width="400" height="400" style="display: none;"></canvas>
<canvas id="canHid" width="400" height="400" style="display: none;"></canvas>
<canvas id="canRend" width="400" height="400" style="border:1px dotted #eee;"></canvas>
</div>
</body>
</html>
In some way, you would need to keep track on the changes you make to a shape you draw on the canvas. In your case, you would start by creating a very small rectangle and then scale it according to your mouse position during your dragmove.
Currently, you only have a function which draws an entirely new rectangle but does not take any previous "state" into consideration.
I found this blogpost which could be helpful. It doesn't explain scaling in particular but it could help with the basic concepts behind so I think this would be a good way for you to find a suitable solution.
Since we are finding the canvas tag in the DOM using it’s id and then setting the drawing context of the canvas to 2D. Two things is importent here is store the information as we draw the recatangle and a bolean to check user is drawing the rectangleor not.
You can reffer these links:Drawing a rectangle using click, mouse move, and click
Draw on HTML5 Canvas using a mouse
Check the js fiddle in the given link.
Hope this will help you..
Your current code has the redraw commented out on the mouse move, which would be required to update the canvas. However your code is also destroying the image the way the rectangle is being drawn. If you retain the image as shown below and redraw it on each frame before drawing the rectangle, it might have the desired effect.
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
currShape = 'rectangle',
mouseIsDown = 0,
startX, endX, startY, endY,
dot_flag = false;
var x = "white",
y = 2,
image = null;
function init() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
var imageObj = new Image(); //Canvas image Obj
imageObj.onload = function() {
image = imageObj;
ctx.drawImage(image, 69, 50); //Load Image on canvas
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'; //Load Image
w = canvas.width; // Canvas Width
h = canvas.height; // Canvas Height
//Check Shape to be draw
eventListener();
}
function eventListener(){
if(currShape=='rectangle'){
canvas.addEventListener("mousedown",function (e) {
mouseDown(e);
}, false);
canvas.addEventListener("mousemove",function (e){
mouseXY(e);
}, false);
canvas.addEventListener("mouseup", function (e){
mouseUp(e);
}, false);
}
}
function mouseUp(eve) {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
if(currShape=='rectangle')
{
drawSquare(); //update on mouse-up
}
}
}
function mouseDown(eve) {
mouseIsDown = 1;
var pos = getMousePos(canvas, eve);
startX = endX = pos.x;
startY = endY = pos.y;
if(currShape=='rectangle')
{
drawSquare(); //update on mouse-up
}
}
function mouseXY(eve) {
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
drawSquare();
}
}
function drawSquare() {
// draw background image
if(image) {
ctx.drawImage(image, 69, 50);
}
// creating a square
var w = endX - startX;
var h = endY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
ctx.beginPath();
ctx.globalAlpha=0.7;
ctx.rect(startX + offsetX, startY + offsetY, width, height);
ctx.fillStyle = x;
ctx.fill();
ctx.lineWidth = y;
ctx.strokeStyle = x;
ctx.stroke();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
.colortool div {
width: 15px;
height: 15px;
float: left;
margin-left: 2px;
}
.clear {
clear: both;
}
<!DOCTYPE HTML>
<html>
<body onload="init()">
<div class="canvasbody">
<canvas id="can" width="400" height="400" style="border:1px dotted #eee;"></canvas>
</div>
</body>
</html>
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 used this Resize an image with javascript for use inside a canvas createPattern to resize the initial image, but when I try to put the same code in my drag/drop functionality, it does not work correctly (it creates a new image and when I try to drag it, it gets strange - see image below. the "O" has the image before dragging/dropping, the "P" has the image after dragging/dropping).
Here is the code I am using:
function photos_create_preview_image(element)
{
console.log(element.id);
if(element.id.indexOf("canvas") != -1)
{
var canvas = document.getElementById(element.id);
var ctx = canvas.getContext("2d");
var canvasOffset = $("#" + element.id).offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var isDown = false;
var startX;
var startY;
var imgX = 0;
var imgY = 0;
var imgWidth, imgHeight;
var mouseX, mouseY;
var new_img = new Image();
new_img.onload = function()
{
var tempCanvas = photos_create_temp_canvas(new_img);
imgWidth = new_img.width;
imgHeight = new_img.height;
//var pattern = ctx.createPattern(new_img, "no-repeat");
var pattern = ctx.createPattern(tempCanvas, "no-repeat");
ctx.fillStyle = pattern;
ctx.fill();
};
new_img.src = SITE_URL + "/system/photo/cf_preview/" + selected_fid;
function photos_create_temp_canvas(new_img)
{
var tempCanvas = document.createElement("canvas"),
tCtx = tempCanvas.getContext("2d");
tempCanvas.width = new_img.width / 3; //TODO: Figure out what this should be, right now it is just a "magic number"
tempCanvas.height = new_img.height / 3 ;
tCtx.drawImage(new_img,0,0,new_img.width,new_img.height,0,0,new_img.width / 3,new_img.height / 3);
return tempCanvas;
}
function handleMouseDown(e)
{
e.preventDefault();
startX = parseInt(e.pageX - window.scrollX);
startY = parseInt(e.pageY - window.scrollY);
if (startX >= imgX && startX <= imgX + imgWidth && startY >= imgY && startY <= imgY + imgHeight) {
isDown = true;
}
}
function handleMouseUp(e)
{
e.preventDefault();
isDown = false;
}
function handleMouseOut(e)
{
e.preventDefault();
isDown = false;
}
function handleMouseMove(e)
{
if (!isDown) {
return;
}
e.preventDefault();
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
if (!isDown) {
return;
}
imgX += mouseX - startX;
imgY += mouseY - startY;
startX = mouseX;
startY = mouseY;
var tempCanvas = photos_create_temp_canvas(new_img);
var pattern = ctx.createPattern(tempCanvas, "no-repeat");
//var pattern = ctx.createPattern(new_img, "no-repeat");
ctx.save();
ctx.translate(imgX, imgY);
ctx.fillStyle = pattern;
ctx.fill();
ctx.restore();
}
$("#" + element.id).mousedown(function (e) {
handleMouseDown(e);
});
$("#" + element.id).mousemove(function (e) {
handleMouseMove(e);
});
$("#" + element.id).mouseup(function (e) {
handleMouseUp(e);
});
$("#" + element.id).mouseout(function (e) {
handleMouseOut(e);
});
}
else //You can ignore this - not relevant to the question
{
new_img = new Image();
new_img.onload = function() {
this.width /= 3; //TODO: Figure out what this should be, right now it is just a "magic number"
this.height /= 3;
element.appendChild(new_img);
$(new_img).draggable({ containment: "parent" });
};
new_img.src = SITE_URL + "/system/photo/cf_preview/" + selected_fid;
}
console.log("new image: " + new_img.src);
}
I changed the code to:
...
ctx.fillStyle = "#BFBFBF";
ctx.fill();
var tempCanvas = photos_create_temp_canvas(new_img);
var pattern = ctx.createPattern(tempCanvas, "no-repeat");
ctx.save();
ctx.translate(imgX, imgY);
ctx.fillStyle = pattern;
ctx.fill();
ctx.restore();
...
And that part works but, now it is only letting me move the image from the bottom. (See image below)
You need to clear the canvas before redrawing:
function handleMouseMove(e)
{
...
var tempCanvas = photos_create_temp_canvas(new_img);
var pattern = ctx.createPattern(tempCanvas, "no-repeat");
//var pattern = ctx.createPattern(new_img, "no-repeat");
ctx.save();
ctx.translate(imgX, imgY);
ctx.fillStyle = pattern;
ctx.clearRect(0, 0, tempCanvas.width, tempCanvas.height);
ctx.fill();
ctx.restore();
}
http://jsfiddle.net/cs5Sg/11/
I want to do the scalable canvas. I created two circles (arcs) and one line, when you click on circle and move it, the line will follow and change position. The problem is when I added code for resize:
var canvas = document.getElementById('myCanvas'),
context = canvas.getContext('2d'),
radius = 12,
p = null,
point = {
p1: { x:100, y:250 },
p2: { x:400, y:100 }
},
moving = false;
window.addEventListener("resize", OnResizeCalled, false);
function OnResizeCalled() {
var gameWidth = window.innerWidth;
var gameHeight = window.innerHeight;
var scaleToFitX = gameWidth / 800;
var scaleToFitY = gameHeight / 480;
var currentScreenRatio = gameWidth / gameHeight;
var optimalRatio = Math.min(scaleToFitX, scaleToFitY);
if (currentScreenRatio >= 1.77 && currentScreenRatio <= 1.79) {
canvas.style.width = gameWidth + "px";
canvas.style.height = gameHeight + "px";
}
else {
canvas.style.width = 800 * optimalRatio + "px";
canvas.style.height = 480 * optimalRatio + "px";
}
}
function init() {
return setInterval(draw, 10);
}
canvas.addEventListener('mousedown', function(e) {
for (p in point) {
var
mouseX = e.clientX - 1,
mouseY = e.clientY - 1,
distance = Math.sqrt(Math.pow(mouseX - point[p].x, 2) + Math.pow(mouseY - point[p].y, 2));
if (distance <= radius) {
moving = p;
break;
}
}
});
canvas.addEventListener('mouseup', function(e) {
moving = false;
});
canvas.addEventListener('mousemove', function(e) {
if(moving) {
point[moving].x = e.clientX - 1;
point[moving].y = e.clientY - 1;
}
});
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.moveTo(point.p1.x,point.p1.y);
context.lineTo(point.p2.x,point.p2.y);
context.closePath();
context.fillStyle = '#8ED6FF';
context.fill();
context.stroke();
for (p in point) {
context.beginPath();
context.arc(point[p].x,point[p].y,radius,0,2*Math.PI);
context.fillStyle = 'red';
context.fill();
context.stroke();
}
context.closePath();
}
init();
The canvas is scalable, but the problem is with the points (circles). When you change the window size, they still have the same position on the canvas area, but the distance change (so the click option fails). How to fix that?
Live Demo
Basically you just need a scaler value that takes into account the actual dimensions of the canvas, and the css dimensions like so
var scaledX = canvas.width/ canvas.offsetWidth,
scaledY = canvas.height/ canvas.offsetHeight;
And then every time the window is resized you need to make sure to update the scaler values.
function OnResizeCalled() {
scaledX = canvas.width/ canvas.offsetWidth;
scaledY = canvas.height/ canvas.offsetHeight;
}
To get the correct coords you need to multiply the clientX and clientY by the scaler in all of your mouse events
canvas.addEventListener('mousedown', function(e) {
for (p in point) {
var
mouseX = e.clientX*scaledX,
mouseY = e.clientY*scaledY,
distance = Math.sqrt(Math.pow(mouseX - point[p].x, 2) + Math.pow(mouseY - point[p].y, 2));
if (distance <= radius) {
moving = p;
break;
}
}
});
canvas.addEventListener('mousemove', function(e) {
var mouseX = e.clientX*scaledX,
mouseY = e.clientY*scaledY;
if(moving) {
point[moving].x = mouseX;
point[moving].y = mouseY;
}
});
Full code
var canvas = document.getElementById('myCanvas'),
context = canvas.getContext('2d'),
radius = 12,
p = null,
point = {
p1: { x:100, y:250},
p2: { x:400, y:100}
},
moving = false,
scaledX = canvas.width/ canvas.offsetWidth,
scaledY = canvas.height/ canvas.offsetHeight;
window.addEventListener("resize", OnResizeCalled, false);
function OnResizeCalled() {
var gameWidth = window.innerWidth;
var gameHeight = window.innerHeight;
var scaleToFitX = gameWidth / 800;
var scaleToFitY = gameHeight / 480;
var currentScreenRatio = gameWidth / gameHeight;
var optimalRatio = Math.min(scaleToFitX, scaleToFitY);
if (currentScreenRatio >= 1.77 && currentScreenRatio <= 1.79) {
canvas.style.width = gameWidth + "px";
canvas.style.height = gameHeight + "px";
}
else {
canvas.style.width = 800 * optimalRatio + "px";
canvas.style.height = 480 * optimalRatio + "px";
}
scaledX = canvas.width/ canvas.offsetWidth;
scaledY = canvas.height/ canvas.offsetHeight;
}
function init() {
return setInterval(draw, 10);
}
canvas.addEventListener('mousedown', function(e) {
for (p in point) {
var
mouseX = e.clientX*scaledX,
mouseY = e.clientY*scaledY,
distance = Math.sqrt(Math.pow(mouseX - point[p].x, 2) + Math.pow(mouseY - point[p].y, 2));
if (distance <= radius) {
moving = p;
break;
}
}
});
canvas.addEventListener('mouseup', function(e) {
moving = false;
});
canvas.addEventListener('mousemove', function(e) {
var mouseX = e.clientX*scaledX,
mouseY = e.clientY*scaledY;
if(moving) {
point[moving].x = mouseX; //1 is the border of your canvas
point[moving].y = mouseY;
}
});
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.moveTo(point.p1.x,point.p1.y);
context.lineTo(point.p2.x,point.p2.y);
context.closePath();
context.fillStyle = '#8ED6FF';
context.fill();
context.stroke();
for (p in point) {
context.beginPath();
context.arc(point[p].x,point[p].y,radius,0,2*Math.PI);
context.fillStyle = 'red';
context.fill();
context.stroke();
}
context.closePath();
}
init();