I want to find out if it is possible to get multiple drawing lines just like this Fiddle project -
However with out using the canvas, instead using a normal div box with a css background image?
below code using canvas
var canvas = new fabric.Canvas('c', { selection: false });
var line, isDown;
canvas.on('mouse:down', function(o){
isDown = true;
var pointer = canvas.getPointer(o.e);
var points = [ pointer.x, pointer.y, pointer.x, pointer.y ];
line = new fabric.Line(points, {
strokeWidth: 5,
fill: 'red',
stroke: 'red',
originX: 'center',
originY: 'center'
});
canvas.add(line);
});
canvas.on('mouse:move', function(o){
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
line.set({ x2: pointer.x, y2: pointer.y });
canvas.renderAll();
});
canvas.on('mouse:up', function(o){
isDown = false;
});
Thanks
I made some correction to the example to draw in all direction , and that's only with css3 :
Note that you have to define to point (two clicks ) to draw a line .
See below snippet :
$(function() {
var x1 = null,
y1 = null;
var offsetX = 0,
offsetY = 0;
function createLine(x1, y1, x2, y2) {
var length = Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
var angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
var transform = 'rotate(' + angle + 'deg)';
offsetX = (x1 > x2) ? x2 : x1;
offsetY = (y1 > y2) ? y2 : y1;
var line = $('<div>')
.appendTo('#demo')
.addClass('line')
.css({
'position': 'absolute',
'-webkit-transform': transform,
'-moz-transform': transform,
'transform': transform
})
.width(length)
.offset({
left: offsetX,
top: offsetY
});
return line;
}
$('#demo').click(function(event) {
var x = event.pageX,
y = event.pageY;
if (x1 == null) {
x1 = x;
y1 = y;
} else {
createLine(x1, y1, x, y);
x1 = y1 = null;
}
})
.delegate('.line', 'click', function(event) {
event.preventDefault();
$(this).toggleClass('active');
x1 = y1 = null;
return false;
});
});
div.line {
transform-origin: 0 100%;
height: 3px;
/* Line width of 3 */
background: #000;
/* Black fill */
}
#demo {
border: 1px dashed #ccc;
height: 400px;
}
div.transforming-on-corner {
transform-origin: 0% 0%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3> click two point to draw a line :</h3>
<div id="demo" class="wide">
</div>
Related
I'm trying to make a canvas with the ability to draw (with mousedown) paths that are filled with a color like so:
I have this code that kinda works but it's crashing usually when I start to draw, probably because of its too much calculation load on the plotLine function.
I'm wondering if I can do this more efficiently to prevent the crash if possible.
// Some setup code
var c = document.querySelector("canvas"),
ctx = c.getContext("2d"),
colors = [
{ r: 198, g: 232, b: 250 },
{ r: 249, g: 213, b: 228 },
{ r: 254, g: 250, b: 214 }
],
cIndex = 0,
maxColors = colors.length,
total = 0,
segment = 500,
isDown = false,
px,
py;
setSize();
c.onmousedown = c.ontouchstart = function(e) {
isDown = true;
var pos = getPos(e);
px = pos.x;
py = pos.y;
};
window.onmousemove = window.ontouchmove = function(e) {
if (isDown) plot(e);
};
window.onmouseup = window.ontouchend = function(e) {
e.preventDefault();
isDown = false;
};
function getPos(e) {
e.preventDefault();
if (e.touches) e = e.touches[0];
var r = c.getBoundingClientRect();
return {
x: e.clientX - r.left,
y: e.clientY - r.top
};
}
function plot(e) {
var pos = getPos(e);
plotLine(ctx, px, py, pos.x, pos.y);
px = pos.x;
py = pos.y;
}
function plotLine(ctx, x1, y1, x2, y2) {
var diffX = Math.abs(x2 - x1),
diffY = Math.abs(y2 - y1),
dist = Math.sqrt(diffX * diffX + diffY * diffY),
step = dist / 50,
i = 0,
t,
b,
x,
y;
while (i <= dist) {
t = Math.min(1, i / dist);
x = x1 + (x2 - x1) * t;
y = y1 + (y2 - y1) * t;
ctx.fillStyle = getColor();
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI * 2);
ctx.fill();
i += step;
}
function getColor() {
var r, g, b, t, c1, c2;
c1 = colors[cIndex];
c2 = colors[(cIndex + 1) % maxColors];
t = Math.min(1, total / segment);
if (++total > segment) {
total = 0;
if (++cIndex >= maxColors) cIndex = 0;
}
r = c1.r + (c2.r - c1.r) * t;
g = c1.g + (c2.g - c1.g) * t;
b = c1.b + (c2.b - c1.b) * t;
return "rgb(" + (r | 0) + "," + (g | 0) + "," + (b | 0) + ")";
}
}
window.onresize = setSize;
function setSize() {
c.width = window.innerWidth;
c.height = window.innerHeight;
}
document.querySelector("button").onclick = function() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
};
html,
body {
background: #777;
margin: 0;
overflow: hidden;
}
canvas {
position: fixed;
left: 0;
top: 0;
background: #333;
}
button {
position: fixed;
left: 10px;
top: 10px;
}
<canvas></canvas>
<button>Clear</button>
In the function plotLine there is a risk that dist and step are 0. In that case the while loop will never end.
So just add this line:
if (!step) return;
Or, else replace <= by < in the loop condition:
while (i < dist) {
Im having issues with this code created. The problem im having is when i click to stop the line from drawing its has a 50% chance it will work first time However It only seems work correctly if you are doing straight lines only, but i want it to work from any direction and im not 100% sure why its not working line that.
(Im using 1.12.4 jquery as im adding this into WordPress thats what is runs off)
$(function() {
var x1 = null,
y1 = null;
var offsetX = 0,
offsetY = 0;
var moveLineId = "moveLine";
function createLine(x1, y1, x2, y2, id) {
var length = Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
var angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
var transform = 'rotate(' + angle + 'deg)';
offsetX = (x1 > x2) ? x2 : x1;
offsetY = (y1 > y2) ? y2 : y1;
var line = $('<div>')
.appendTo('#demo')
.addClass('line')
.css({
'position': 'absolute',
'-webkit-transform': transform,
'-moz-transform': transform,
'transform': transform
})
.width(length)
.offset({
left: offsetX,
top: offsetY
});
if(id != null) line.attr('id', id);
return line;
}
$('#demo').click(function(event) {
$(".line").removeAttr('id');
var x = event.pageX,
y = event.pageY;
if (x1 == null) {
x1 = x;
y1 = y;
} else {
x1 = y1 = null;
}
})
.delegate('.line', 'click', function(event) {
event.preventDefault();
$(this).toggleClass('active');
x1 = y1 = null;
return false;
});
$('#demo').mousemove(function(event) {
var x = event.pageX,
y = event.pageY;
if (x1 != null) {
$("#" + moveLineId).remove();
createLine(x1, y1, x, y, moveLineId)
} else {
x1 = y1 = null;
}
})
});
div.line {
transform-origin: 0 100%;
height: 3px;
/* Line width of 3 */
background: #000;
/* Black fill */
}
#demo {
border: 1px dashed #ccc;
height: 400px;
}
div.transforming-on-corner {
transform-origin: 0% 0%;
}
<script src="https://code.jquery.com/jquery-1.12.4.min.js"
integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="
crossorigin="anonymous"></script>
<h3> click two point to draw a line :</h3>
<div id="demo" class="wide">
</div>
Instead of click events, listen to mousedown and mouseup events to start / stop drawing the line.
$(function() {
var x1 = null,
y1 = null;
var offsetX = 0,
offsetY = 0;
var moveLineId = "moveLine";
// Use "mousedown" here so the start of a line is registered as soon as you press the mouse button.
$('#demo').on("mousedown", function(event) {
$(".line").removeAttr('id');
var x = event.pageX,
y = event.pageY;
if (x1 == null) {
x1 = x;
y1 = y;
} else {
x1 = y1 = null;
}
})
.delegate('.line', 'mouseup', function(event) {
// Use "mouseup" here so the start of a line is registered as soon as you release the mouse button.
event.preventDefault();
$(this).toggleClass('active');
x1 = y1 = null;
return false;
});
$('#demo').mousemove(function(event) {
var x = event.pageX,
y = event.pageY;
if (x1 != null) {
$("#" + moveLineId).remove();
createLine(x1, y1, x, y, moveLineId)
} else {
x1 = y1 = null;
}
});
function createLine(x1, y1, x2, y2, id) {
var length = Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
var angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
var transform = 'rotate(' + angle + 'deg)';
offsetX = (x1 > x2) ? x2 : x1;
offsetY = (y1 > y2) ? y2 : y1;
var line = $('<div>')
.appendTo('#demo')
.addClass('line')
.css({
'position': 'absolute',
'-webkit-transform': transform,
'-moz-transform': transform,
'transform': transform
})
.width(length)
.offset({
left: offsetX,
top: offsetY
});
if (id != null) line.attr('id', id);
return line;
}
});
div.line {
transform-origin: 0 100%;
height: 3px;
background: #000;
}
#demo {
border: 1px dashed #ccc;
height: 400px;
}
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
<div id="demo" class="wide"></div>
im trying to get the line drawing to show on first click. So you are able to see where the line will end on second click. At the moment you cant see the line until you click a second point but i cant work out what im missing so that the line shows up on the first click and it carries on displaying until the second click.
$(function() {
var x1 = null,
y1 = null;
var offsetX = 0,
offsetY = 0;
function createLine(x1, y1, x2, y2) {
var length = Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
var angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
var transform = 'rotate(' + angle + 'deg)';
offsetX = (x1 > x2) ? x2 : x1;
offsetY = (y1 > y2) ? y2 : y1;
var line = $('<div>')
.appendTo('#demo')
.addClass('line')
.css({
'position': 'absolute',
'-webkit-transform': transform,
'-moz-transform': transform,
'transform': transform
})
.width(length)
.offset({
left: offsetX,
top: offsetY
});
return line;
}
$('#demo').click(function(event) {
var x = event.pageX,
y = event.pageY;
if (x1 == null) {
x1 = x;
y1 = y;
} else {
createLine(x1, y1, x, y);
x1 = y1 = null;
}
})
.delegate('.line', 'click', function(event) {
event.preventDefault();
$(this).toggleClass('active');
x1 = y1 = null;
return false;
});
});
div.line {
transform-origin: 0 100%;
height: 3px;
/* Line width of 3 */
background: #000;
/* Black fill */
}
#demo {
border: 1px dashed #ccc;
height: 400px;
}
div.transforming-on-corner {
transform-origin: 0% 0%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3> click two point to draw a line :</h3>
<div id="demo" class="wide">
</div>
One thing you can do is draw a unique line on the $('#demo').mousemove event after your first click. On each move remove that line by referencing its id (ex: #moveLine) and draw the new one at your mouse position. Once you click to draw a new line it will clear the id of the old line so it becomes permanent.
$(function() {
var x1 = null,
y1 = null;
var offsetX = 0,
offsetY = 0;
var moveLineId = "moveLine";
function createLine(x1, y1, x2, y2, id) {
var length = Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
var angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
var transform = 'rotate(' + angle + 'deg)';
offsetX = (x1 > x2) ? x2 : x1;
offsetY = (y1 > y2) ? y2 : y1;
var line = $('<div>')
.appendTo('#demo')
.addClass('line')
.css({
'position': 'absolute',
'-webkit-transform': transform,
'-moz-transform': transform,
'transform': transform
})
.width(length)
.offset({
left: offsetX,
top: offsetY
});
if(id != null) line.attr('id', id);
return line;
}
$('#demo').click(function(event) {
$(".line").removeAttr('id');
var x = event.pageX,
y = event.pageY;
if (x1 == null) {
x1 = x;
y1 = y;
} else {
x1 = y1 = null;
}
})
.delegate('.line', 'click', function(event) {
event.preventDefault();
$(this).toggleClass('active');
x1 = y1 = null;
return false;
});
$('#demo').mousemove(function(event) {
var x = event.pageX,
y = event.pageY;
if (x1 != null) {
$("#" + moveLineId).remove();
createLine(x1, y1, x, y, moveLineId)
} else {
x1 = y1 = null;
}
})
});
div.line {
transform-origin: 0 100%;
height: 3px;
/* Line width of 3 */
background: #000;
/* Black fill */
}
#demo {
border: 1px dashed #ccc;
height: 400px;
}
div.transforming-on-corner {
transform-origin: 0% 0%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3> click two point to draw a line :</h3>
<div id="demo" class="wide">
</div>
Right now I have a circle that goes from the bottom to the top of a canvas.
I attached a click event to the canvas and it console logs the coordinates of the click.
The ball also console logs the coordinates of where it is.
How can I add a circle element to 'elements' and how do I compare the canvas click event to the circle diameters coordinates.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var ballRadius = 10;
var x = canvas.width/6;
var y = canvas.height-30;
var dx = 0;
var dy = -2;
canvas.addEventListener('click', function(event) {
var x = event.pageX - elemLeft;
var y = event.pageY - elemTop;
console.log("CLICKED: (x,y) ", x, y);
elements.forEach(function(element) {
if (y > canvas.y && y < canvas.y + canvas.ballRadius && x > canvas.x && x < canvas.x + canvas.ballRadius) {
alert('clicked an element');
}
});
}, false);
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();
console.log("Ball moving: (x,y) ", x, ", ", y)
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
dy = -dy;
}
x += dx;
y += dy;
}
setInterval(draw, 100);
https://jsfiddle.net/aL9amevj/
You can use css to render a circle, .animate() to animate element, check if animation animation.currentTime is less than half of animation.effect.computedTiming.duration / 2 .finished to reset element to original state.
.circle {
position: relative;
border-radius: 50%;
width: 50px;
height: 50px;
background: blue;
left: calc(100vw - 100px);
top: calc(100vh - 100px);
}
<button>click</button>
<div class="circle" style="animation-fill-mode:forwards"></div>
<script>
var score = 0;
var button = document.querySelector("button");
var circle = document.querySelector(".circle");
button.addEventListener("click", function() {
this.setAttribute("disabled", "disabled");
var curr = circle.animate([{
left: "0px",
top: "0px"
}], {
duration: 10000,
iterations: 1
});
circle.onclick = (e) => {
console.log(e.pageX, e.pageY);
var t = curr.currentTime <
curr.effect.computedTiming.duration / 2;
if (t) {
score += 1;
}
curr.cancel();
circle.style.display = "none";
circle.onclick = null;
alert((t ? "added 1 " : "did not add 1 ")
+ "to score: " + score);
}
curr.finished.then(() => {
circle.onclick = null;
setTimeout(function() {
button.removeAttribute("disabled");
}, 10)
}).catch(e => {
console.log(e);
button.removeAttribute("disabled");
circle.style.display = "block";
})
});
</script>
I found this in a stackoverflow question on how to draw in canvas http://jsfiddle.net/ArtBIT/kneDX/ but I want it to draw lines continuously without the circles but smooth lines. The code to be changed is below:
ctx.fillCircle = function(x, y, radius, fillColor) {
this.fillStyle = fillColor;
this.beginPath();
this.moveTo(x, y);
this.arc(x, y, radius, 0, Math.PI * 2, false);
this.fill();
};
You can use Bresenham's line algorithm to find all the points between the mouse start and end, and then fill the points between using fillRect. The reason you need to use the line algorithm is because if a user moves the mouse too fast you wont get solid lines, but lines with gaps. I modified your function quite a bit to do this. You can also pass a line thickness value to change how large you want the stroke to be. Note the same could be applied using arcs I just prefer rect
Live Demo
(function() {
// Creates a new canvas element and appends it as a child
// to the parent element, and returns the reference to
// the newly created canvas element
function createCanvas(parent, width, height) {
var canvas = {};
canvas.node = document.createElement('canvas');
canvas.context = canvas.node.getContext('2d');
canvas.node.width = width || 100;
canvas.node.height = height || 100;
parent.appendChild(canvas.node);
canvas.lastX = 0;
canvas.lastY = 0;
return canvas;
}
function init(container, width, height, fillColor) {
var canvas = createCanvas(container, width, height);
var ctx = canvas.context;
// define a custom fillCircle method
ctx.fillCircle = function(x1, y1, x2, y2, fillColor, lineThickness) {
this.fillStyle = fillColor;
var steep = (Math.abs(y2 - y1) > Math.abs(x2 - x1));
if (steep) {
var x = x1;
x1 = y1;
y1 = x;
var y = y2;
y2 = x2;
x2 = y;
}
if (x1 > x2) {
var x = x1;
x1 = x2;
x2 = x;
var y = y1;
y1 = y2;
y2 = y;
}
var dx = x2 - x1,
dy = Math.abs(y2 - y1),
error = 0,
de = dy / dx,
yStep = -1,
y = y1;
if (y1 < y2) {
yStep = 1;
}
for (var x = x1; x < x2; x++) {
if (steep) {
this.fillRect(y, x, lineThickness, lineThickness);
} else {
this.fillRect(x, y, lineThickness, lineThickness);
}
error += de;
if (error >= 0.5) {
y += yStep;
error -= 1.0;
}
}
};
ctx.clearTo = function(fillColor) {
ctx.fillStyle = fillColor;
ctx.fillRect(0, 0, width, height);
};
ctx.clearTo(fillColor || "#ddd");
// bind mouse events
canvas.node.onmousemove = function(e) {
if (!canvas.isDrawing) {
return;
}
mouseX = e.pageX - this.offsetLeft;
mouseY = e.pageY - this.offsetTop;
ctx.fillCircle(mouseX,mouseY,canvas.lastX,canvas.lastY,"#000",1);
canvas.lastX = mouseX;
canvas.lastY = mouseY;
};
canvas.node.onmousedown = function(e) {
canvas.isDrawing = true;
canvas.lastX = e.pageX - this.offsetLeft;
canvas.lastY = e.pageY - this.offsetTop;
};
canvas.node.onmouseup = function(e) {
canvas.isDrawing = false;
};
}
var container = document.getElementById('canvas');
init(container, 200, 200, '#ddd');
})();
If i understand,you need this: http://www.html5canvastutorials.com/tutorials/html5-canvas-lines/
This script draw a line from 0,0 to mouse.
window.event.clientX = mouse x coordinate
window.event.clientY = mouse y coordinate
<script>
context.beginPath();
context.moveTo(0,0);
context.lineTo(window.event.clientX,window.event.clientY);
context.stroke();
</script>