I'm trying to to make it possible for an image on a canvas to have a box over it with low opacity, to make it be shown that it has been selected. So I need an onclick function, but i'm stuck on what to do. Any advice? I would aslo appreciate if someone could point me in the right direction on how to make the box also pulsate.
var image1 = new Kinetic.Image({
image: imageObj,
x: xposition,
y: yposition,
width: width,
height: height,
stroke: 'blue',
srokeFill: 'red',
strokeWidth: 5,
draggable: true,
dragBoundFunc: function (pos) {
if (pos.x < this.minX)
this.minX = pos.x;
return {
x: pos.x,
y: this.getAbsolutePosition().y
}
}
});
layer.on('mouseover', function (evt) {
var shape = evt.target;
document.body.style.cursor = 'pointer';
shape.strokeEnabled(true);
layer.draw();
});
layer.on('mouseout', function (evt) {
var shape = evt.target;
document.body.style.cursor = 'default';
shape.strokeEnabled(false);
layer.draw();
});
When making a clickable region on a canvas you need to.
- Create a redraw function.
- Find the mouse point inside of canvas.
- Do collision detection on the mouse point and region.
update: added multiple clickable regions.
// x1, y1, x2, y2, clicked
var boxes = [{
x1: 10,
y1: 10,
x2: 110,
y2: 110,
clicked: false
}, {
x1: 120,
y1: 10,
x2: 220,
y2: 110,
clicked: false
}];
function go() {
var can = document.getElementById('can');
var ctx = can.getContext('2d');
var w = can.width;
var h = can.height;
makeNoise(ctx);
var imageData = ctx.getImageData(0, 0, w, h);
var mx = 0;
var my = 0;
$('#can').mousemove(function(event) {
var offset = $(this).offset();
mx = event.pageX - offset.left;
my = event.pageY - offset.top;
redraw();
});
$('#can').click(function(event) {
var offset = $(this).offset();
mx = event.pageX - offset.left;
my = event.pageY - offset.top;
for (var i = 0, len = boxes.length; i < len; i++) {
var b = boxes[i];
if (hit(b.x1, b.y1, b.x2, b.y2)) {
b.clicked = !b.clicked;
}
}
redraw();
});
function redraw() {
// Draw the original image
ctx.putImageData(imageData, 0, 0);
// Draw the clickable region
for (var i = 0, len = boxes.length; i < len; i++) {
drawBox(boxes[i]);
}
// Draw the mouse. Probably only needed when testing
// mouse location.
drawMouse();
}
redraw();
// Collision dection of a square against mouse point.
// square points x1,y1 must be less than x2,y2
function hit(x1, y1, x2, y2) {
if (mx < x1 || my < y1 || mx > x2 || my > y2) return false;
return true;
}
function drawMouse() {
ctx.moveTo(mx, my);
ctx.fillStyle = "yellow";
ctx.beginPath();
ctx.arc(mx, my, 5, 0, Math.PI * 360);
ctx.fill();
}
function drawBox(b) {
if (b.clicked) {
// Mouse clicked.
ctx.fillStyle = "rgba(255,0,255,.5)"
} else if (hit(b.x1, b.y1, b.x2, b.y2)) {
// Mouse Over
ctx.fillStyle = "rgba(255,255,255,.5)"
} else {
// Mouse Out
ctx.fillStyle = "red";
}
ctx.fillRect(b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1);
}
}
// Fill a canvas context with noise.
function makeNoise(ctx) {
var can = ctx.canvas;
var imageData = ctx.getImageData(0, 0, can.width, can.height);
var d = imageData.data;
for (var i = 0, len = d.length; i < len; i += 4) {
d[i] = d[i + 1] = d[i + 2] = (Math.random() * 8) << 4;
d[i + 3] = 255;
}
ctx.putImageData(imageData, 0, 0);
}
go();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="can" width="400" height="300"></canvas>
Related
Following is my code. I have face issue when I drag a point. The problem is that whenever I drag point all the line connect to one point. I need to have draggable points in a html5 Canvas. But I have a supplementary constraint: the 2 points must be linked by a line. When I drag a point, the line must be dynamically drawn, and still linked to the 2 points.
let points= [];
let drag_point= -1;
let pointSize= 6;
let canvas = document.querySelector("#myCanvas");
let w = canvas.width;
let h = canvas.height;
var ctx = canvas.getContext("2d");
$("#myCanvas").mousedown(function (e) {
var pos = getPosition(e);
drag_point = getPointAt(pos.x, pos.y);
console.log("pos", drag_point);
if (drag_point == -1) {
// no point at that position, add new point
drawlines(pos.x, pos.y);
points.push(pos);
}
});
$("#myCanvas").mousemove(function (e) {
if (drag_point != -1) {
// if currently dragging a point...
var pos = getPosition(e);
//...update that.points position...
points[drag_point].x = pos.x;
points[drag_point].y = pos.y;
redraw(); // ... and redraw myCanvas
}
});
$("#myCanvas").mouseup(function (e) {
drag_point = -1;
});
function getPosition(event) {
var rect = canvas.getBoundingClientRect();
var x = event.clientX - rect.left;
var y = event.clientY - rect.top;
console.log(x, y);
return { x: x, y: y };
}
function getPointAt(x, y) {
for (var i = 0; i < points.length; i++) {
if (
Math.abs(points[i].x - x) < pointSize &&
Math.abs(points[i].y - y) < pointSize
)
// check if x,y is inside points bounding box. replace with pythagoras theorem if you like.
return i;
}
return -1; // no point at x,y
}
function redraw() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // clear canvas
for (var i = 0; i < points.length; i++) {
// draw all points again
drawlines(points[i].x, points[i].y);
}
}
function drawlines(x, y) {
drawImages(x, y);
if (points.length > 0) {
var last = points[points.length - 1];
ctx.beginPath();
ctx.moveTo(last.x, last.y);
ctx.lineTo(x, y);
ctx.strokeStyle = "blue";
ctx.stroke();
}
}
function drawImages(x, y) {
var ctx = document.getElementById("myCanvas").getContext("2d");
ctx.beginPath();
ctx.arc(x, y, pointSize, 0, Math.PI * 2, true);
ctx.strokeStyle = "red";
ctx.stroke();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas
id="myCanvas"
width="1000"
height="1000"
style="border: 1px solid #d3d3d3"
></canvas>
.
See code below...
I refactored your drawlines and drawImages to be called independently not inside a common loop, in my code we draw all lines, then we draw all circles, that way we don't have to change colors back and forth all the time and prevents any overlaps of the lines over the circles, also another change is in the mousedown I call the redraw instead of drawlines.
Looking at your code educated guess the problem is in your:
var last = points[points.length - 1];
that seems very off, technically that is making the last always be the same
let points = [{x:10,y:10},{x:55,y:50},{x:100,y:10}];
let drag_point = -1;
let pointSize = 6;
let canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
canvas.onmousedown = function(e) {
var pos = getPosition(e);
drag_point = getPointAt(pos.x, pos.y);
if (drag_point == -1) {
points.push(pos);
redraw();
}
};
canvas.onmousemove = function(e) {
if (drag_point != -1) {
var pos = getPosition(e);
points[drag_point].x = pos.x;
points[drag_point].y = pos.y;
redraw();
}
};
canvas.onmouseup = function(e) {
drag_point = -1;
};
function getPosition(event) {
var rect = canvas.getBoundingClientRect();
var x = event.clientX - rect.left;
var y = event.clientY - rect.top;
return {x, y};
}
function getPointAt(x, y) {
for (var i = 0; i < points.length; i++) {
if (
Math.abs(points[i].x - x) < pointSize &&
Math.abs(points[i].y - y) < pointSize
)
return i;
}
return -1;
}
function redraw() {
if (points.length > 0) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawLines()
drawCircles()
}
}
function drawLines() {
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
ctx.strokeStyle = "blue";
ctx.lineWidth = 2;
points.forEach((p) => {
ctx.lineTo(p.x, p.y);
})
ctx.stroke();
}
function drawCircles() {
ctx.strokeStyle = "red";
ctx.lineWidth = 4;
points.forEach((p) => {
ctx.beginPath();
ctx.arc(p.x, p.y, pointSize, 0, Math.PI * 2, true);
ctx.stroke();
})
}
redraw()
<canvas id="myCanvas" width=160 height=160 style="border: 1px solid"></canvas>
I need advice on how to make an event and draw mouse lines in the grid. Somehow I can't do it so I can draw straight lines in a grid. But I still have a grid, I don't know how to fix a drawing error. I am adding my Javascript code below. My mouse drawing event doesn't work, it doesn't draw me at all.
JS code for grid:
;(function () {
let canvas, ctx, mouse
class Mouse {
constructor (ctx, x = 0, y = 0) {
this.x = x
this.y = y
this.ctx = ctx
}
set pos (evt) {
const canvasDimensions = canvas.getBoundingClientRect()
this.x = Math.floor(evt.clientX - canvasDimensions.left)
this.y = Math.floor(evt.clientY - canvasDimensions.top)
const { x, y, ctx } = this
const txt = `X: ${x}, Y: ${y}`
ctx.font = '16px Poppins'
const offsetX = x < canvas.width / 2 ? 15 : -ctx.measureText(txt).width - 15
const offsetY = y < canvas.height / 2 ? 20 : -13
ctx.fillText(txt, this.x + offsetX, this.y + offsetY)
}
}
class Line {
constructor (color, lineWidth, startX, startY, endX, endY) {
this.color = color
this.lineWidth = lineWidth
this.startX = startX
this.startY = startY
this.endX = endX
this.endY = endY
}
draw (ctx) {
const { color, lineWidth, startX, startY, endX, endY } = this
ctx.beginPath()
ctx.strokeStyle = color
ctx.lineWidth = lineWidth
ctx.moveTo(startX, startY)
ctx.lineTo(endX, endY)
ctx.stroke()
}
}
class Grid {
constructor (
color = 'black', lineWidth = 0.25, step = 25,
boldNth = 5, boldColor = 'black', boldWidth = 0.25
) {
this.color = color
this.lineWidth = lineWidth
this.step = step
this.boldNth = boldNth
this.boldColor = boldColor
this.boldWidth = boldWidth
this.lines = null
}
createLines () {
const {
color, lineWidth, step,
boldNth, boldColor, boldWidth
} = this
const lines = []
const div = boldNth * step
for (let x = 0; x < canvas.width; x += step) {
const isNth = x % div === 0
lines.push(
isNth
? new Line(boldColor, boldWidth, x, 0, x, canvas.height)
: new Line(color, lineWidth, x, 0, x, canvas.height)
)
}
for (let y = 0; y < canvas.height; y += step) {
const isNth = y % div === 0
lines.push(
isNth
? new Line(boldColor, boldWidth, 0, y, canvas.width, y)
: new Line(color, lineWidth, 0, y, canvas.width, y)
)
}
this.lines = lines
}
drawText (ctx) {
const { step, boldNth, boldColor } = this
ctx.font = '16px Poppins'
ctx.fillStyle = boldColor
ctx.fillText('0', 1, 15)
for (let x = step * boldNth; x < canvas.width; x += step * boldNth) {
ctx.fillText(x, x, 15)
}
for (let y = step * boldNth; y < canvas.height; y += step * boldNth) {
ctx.fillText(y, 0, y + 15)
}
}
draw (ctx) {
if (!this.lines) this.createLines()
this.lines.forEach(line => line.draw(ctx))
this.drawText(ctx)
}
}
function init () {
canvas = document.getElementById('Canvas')
ctx = canvas.getContext('2d')
mouse = new Mouse(ctx)
const grid = new Grid('black', 0.25, 50, 1)
grid.draw(ctx)
canvas.addEventListener('mousemove', (evt) => {
ctx.clearRect(0, 0, canvas.width, canvas.height)
grid.draw(ctx)
mouse.pos = evt
})
canvas.addEventListener('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.addEventListener('mouse:move', function(o){
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
line.set({ x2: pointer.x, y2: pointer.y });
canvas.renderAll();
grid.draw(ctx)
});
canvas.on('mouse:up', function(o){
isDown = false;
grid.draw(ctx)
});
}
document.addEventListener('DOMContentLoaded', init)
})()
you can use this references codereview.stackexchange.com/questions/114702/… my it can help you – Tommy Ferdian Hadimarta 54 secs ago
I'm a beginner and trying to learn to code html here by playing around the codes I found online. And I came across a javascript that basically snip image into several boxes. The code goes like this:
$(function() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw, ch;
// background definition
// OPTION: look at the top-left pixel and assume == background
// then set these vars automatically
var isTransparent = false;
var bkColor = {
r: 255,
g: 255,
b: 255
};
var bkFillColor = "rgb(" + bkColor.r + "," + bkColor.g + "," + bkColor.b + ")";
// load test image
var img = new Image();
img.crossOrigin = "anonymous";
img.onload = start;
img.src = "http://nedroid.com/comics/2010-09-06-guest-comic-jay-fuller.png";
function start() {
// draw the test image on the canvas
cw = canvas.width = img.width / 2;
ch = canvas.height = img.width / 2;
ctx.drawImage(img, 0, 0, cw, ch);
}
function clipBox(data) {
var pos = findEdge(data);
if (!pos.valid) {
return;
}
var bb = findBoundary(pos, data);
clipToImage(bb.x, bb.y, bb.width, bb.height);
if (isTransparent) {
// clear the clipped area
// plus a few pixels to clear any anti-aliasing
ctx.clearRect(bb.x - 2, bb.y - 2, bb.width + 4, bb.height + 4);
} else {
// fill the clipped area with the bkColor
// plus a few pixels to clear any anti-aliasing
ctx.fillStyle = bkFillColor;
ctx.fillRect(bb.x - 2, bb.y - 2, bb.width + 4, bb.height + 4);
}
}
function xyIsInImage(data, x, y) {
// find the starting index of the r,g,b,a of pixel x,y
var start = (y * cw + x) * 4;
if (isTransparent) {
return (data[start + 3] > 25);
} else {
var r = data[start + 0];
var g = data[start + 1];
var b = data[start + 2];
var a = data[start + 3]; // pixel alpha (opacity)
var deltaR = Math.abs(bkColor.r - r);
var deltaG = Math.abs(bkColor.g - g);
var deltaB = Math.abs(bkColor.b - b);
return (!(deltaR < 5 && deltaG < 5 && deltaB < 5 && a > 25));
}
}
function findEdge(data) {
for (var y = 0; y < ch; y++) {
for (var x = 0; x < cw; x++) {
if (xyIsInImage(data, x, y)) {
return ({
x: x,
y: y,
valid: true
});
}
}
}
return ({
x: -100,
y: -100,
valid: false
});
}
function findBoundary(pos, data) {
var x0 = x1 = pos.x;
var y0 = y1 = pos.y;
while (y1 <= ch && xyIsInImage(data, x1, y1)) {
y1++;
}
var x2 = x1;
var y2 = y1 - 1;
while (x2 <= cw && xyIsInImage(data, x2, y2)) {
x2++;
}
return ({
x: x0,
y: y0,
width: x2 - x0,
height: y2 - y0 + 1
});
}
function drawLine(x1, y1, x2, y2) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.strokeStyle = "red";
ctx.lineWidth = 0.50;
ctx.stroke();
}
function clipToImage(x, y, w, h) {
// don't save anti-alias slivers
if (w < 3 || h < 3) {
return;
}
// save clipped area to an img element
var tempCanvas = document.createElement("canvas");
var tempCtx = tempCanvas.getContext("2d");
tempCanvas.width = w;
tempCanvas.height = h;
tempCtx.drawImage(canvas, x, y, w, h, 0, 0, w, h);
var image = new Image();
image.width = w;
image.height = h;
image.src = tempCanvas.toDataURL();
$("#clips").append(image);
}
$("#unbox").click(function() {
var imgData = ctx.getImageData(0, 0, cw, ch);
var data = imgData.data;
clipBox(data);
});
}); // end $(function(){});
body {
background-color: ivory;
}
canvas {
border: 1px solid red;
}
#clips {
border: 1px solid blue;
padding: 5px;
}
img {
margin: 3px;
}
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js">
</script>
<button id="unbox">Clip next sub-image</button><br>
<canvas id="canvas" width=300 height=150></canvas><br>
<h4>Below are images clipped from the canvas above.</h4><br>
<div id="clips"></div>
Nothing happen when I click the button, not even the image is loaded onto the canvas. I searched through various online tutorials and that leads to nothing. I have tried forcefully call out the function using start(); in the <body> section but still it's not working.
Problem is not in the code,
it is in the location of Image, put the image on the same domain or use the image as data uri check CODEPEN for working example.
https://codepen.io/mastersmind/pen/bKNqNP?editors=0011
remove this line
img.crossOrigin = "anonymous";
I'm currently working on a canvas timeline-like animation.
This is what I made so far...
$(function() {
'use strict';
var canvas = document.querySelector('#canvas');
var ctx = canvas.getContext('2d');
var s = 20;
var arr = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100];
var colorP = ['#ff5454', '#ffa144', '#ffe256', '#aaff75', '#8cd8ff', '#b5b6ff', '#b882ff'];
var dots = [];
var rDots = [];
function init() {
var reverse = true;
for (var i = 0; i < 100; i++) {
var dot = new Object();
var height = null;
if (arr.indexOf(i) != -1) {
dot.x = s;
dot.y = 50;
dot.r = 3;
dot.c = 'red';
dot.f = 'rgba(0,0,0,0)';
dot.t = '1';
dot.s = 0;
rDots.push(dot);
} else {
dot.x = s;
dot.y = 50;
dot.r = 1;
dot.c = 'red';
dot.f = '';
dot.t = '';
dot.s = 0;
}
s += 10;
dots.push(dot);
};
function tween() {
height = Math.floor(Math.random() * (75 - 25) + 25);
TweenMax.staggerTo(dots, 5, {
y: height,
yoyo: true,
repeat: 'repeat',
repeatDelay: 1,
ease: Sine.easeInOut
}, 0.5);
};
tween();
setInterval(function() {
tween()
}, 4800);
}
init();
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < dots.length - 1; i++) {
ctx.beginPath();
ctx.moveTo(dots[i].x, dots[i].y);
ctx.lineTo(dots[i + 1].x, dots[i + 1].y);
ctx.lineWidth = 3;
ctx.strokeStyle = 'red';
ctx.stroke();
};
for (var i = 0; i < dots.length; i++) {
ctx.beginPath();
ctx.arc(dots[i].x, dots[i].y, dots[i].r, 0, 2 * Math.PI);
ctx.strokeStyle = dots[i].c;
ctx.lineWidth = 1;
ctx.fillStyle = dots[i].f;
ctx.fill();
ctx.stroke();
ctx.font = dots[i].s + 'px Arial';
ctx.textAlign = 'center';
ctx.fillStyle = '#FFF';
ctx.fillText(dots[i].t, dots[i].x, dots[i].y + 4);
};
setTimeout(function() {
draw();
}, 5);
}
draw();
function hover(e, bool) {
var dot = canvas.getBoundingClientRect();
var x = e.clientX - dot.left;
var y = e.clientY - dot.top;
for (var i = 0; i < rDots.length; i++) {
if (x == rDots[i].x) {
TweenMax.to(rDots[i], 0.1, {
r: 10,
f: 'red',
s: 8
});
$('body').css('cursor', 'pointer');
} else {
TweenMax.to(rDots[i], 0.1, {
r: 3,
f: 'rgba(0,0,0,0)',
s: 0
});
}
};
};
$(canvas).on('mousemove', function(e) {
hover(e, true);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" height="100" width="1050" style="background: #EEE"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenMax.min.js"></script>
The idea is,
I want it to swing randomly (checked)
and when the cursor close in the knot, it will enlarge and show the text in it...
I tried to use x and y axis to do the trick,
but it doesn't work well...
Then I tried to make another function to draw a bigger circle to cover the original knot,
but since my draw() keeping clear the canvas, so I failed again...
Wondering is there any better ways to make it work?
any suggestions or hints are welcome!
You may find jCanvas helpful.
It's a JavaScript library that wraps the HTML5 canvas API, letting you add certain object-like functionality using a jQuery-style syntax. You could refactor your code a bit and use a mouseOver effect rather than binding a mousemove event to the canvas, which will let you create a smother animation.
Also, if you increase the area of the rDots.x that's triggering your animation and set your Tween time interval to something a bit longer than 0.1 that makes the animation slightly less jerky as well.
Not sure if this solves your issue, but I hope it helps!
Ok, I've work my way out.
$(function() {
'use strict';
var dots = [],
eDots = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100],
rDots = [],
stagger = 0;
var canvas = document.querySelector('#canvas'),
ctx = canvas.getContext('2d');
//initialize all the dots obj
function init() {
for (var i = 0; i < 100; i++) {
if (eDots.indexOf(i) != -1) {
var dot = {
xAxis: stagger,
yAxis: 50,
radius: 3,
color: 'rgba(0,0,0,0)',
num: 1,
};
rDots.push(dot);
} else {
var dot = {
xAxis: stagger,
yAxis: 50,
radius: .5,
color: 'rgba(0,0,0,0)',
num: ''
};
}
dots.push(dot);
stagger += 10;
}
};
init();
//Save position property for click event
function getSize() {
for (var i = 0; i < rDots.length; i++) {
rDots[i].top = rDots[i].yAxis - rDots[i].radius;
rDots[i].right = rDots[i].xAxis + rDots[i].radius;
rDots[i].bottom = rDots[i].yAxis + rDots[i].radius;
rDots[i].left = rDots[i].xAxis - rDots[i].radius;
}
}
getSize();
//Hover event dots to change style
function hover() {
$(canvas).bind('mousemove', function(e) {
var dot = canvas.getBoundingClientRect(),
x = e.clientX - dot.left,
y = e.clientY - dot.top;
for (var i = 0; i < rDots.length; i++) {
ctx.beginPath();
ctx.arc(rDots[i].xAxis, rDots[i].yAxis, rDots[i].radius, 0, 2 * Math.PI);
//rDots[i].radius = ctx.isPointInPath(x, y) ? 10 : 3;
//rDots[i].color = ctx.isPointInPath(x, y) ? 'red' : 'rgba(0, 0, 0, 0)';
if (ctx.isPointInPath(x, y)) {
TweenMax.to(rDots[i], 0.1, {
radius: 10,
color: 'red',
});
$(canvas).css({
cursor: 'pointer'
});
return;
} else {
TweenMax.to(rDots[i], 0.1, {
radius: 3,
color: 'rgba(0,0,0,0)'
});
}
ctx.stroke();
ctx.fill();
$(canvas).css({
cursor: 'default'
});
}
});
};
hover();
//Setup click event for functioning purpose
function click(e) {
var dot = canvas.getBoundingClientRect(),
x = e.clientX - dot.left,
y = e.clientY - dot.top;
for (var i = 0; i < rDots.length; i++) {
if (x < rDots[i].right && x > rDots[i].left && y > rDots[i].top && y < rDots[i].bottom) {
console.log('This is dot ' + i);
}
}
};
$(canvas).on('click', function(e) {
click(e);
})
//Let the line start to twist
function tween() {
var height = Math.floor(Math.random() * (75 - 25) + 25);
TweenMax.staggerTo(dots, 4, {
yAxis: height,
yoyo: true,
repeat: 'repeat',
repeatDelay: 1,
ease: Sine.easeInOut
}, 0.5);
setTimeout(function() {
tween();
}, 3800);
}
tween();
//Let's get some paint
function draw() {
//clear canvas for animate
ctx.clearRect(0, 0, canvas.width, canvas.height);
//draw the lines
for (var i = 0; i < dots.length - 1; i++) {
ctx.moveTo(dots[i].xAxis, dots[i].yAxis);
ctx.lineTo(dots[i + 1].xAxis, dots[i + 1].yAxis);
ctx.lineWidth = 3;
ctx.stroke();
}
//draw the dots
for (var i = 0; i < dots.length; i++) {
ctx.beginPath();
ctx.arc(dots[i].xAxis, dots[i].yAxis, dots[i].radius, 0, 2 * Math.PI);
ctx.strokeStyle = 'red';
ctx.strokeWidth = '1px';
ctx.fillStyle = dots[i].color;
ctx.stroke();
ctx.fill()
};
setTimeout(function() {
draw();
}, 10);
}
draw();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenMax.min.js"></script>
<canvas id="canvas" height="100" width="1000" style="background:#EEE"></canvas>
Turn's out all I need is to do is use isPointOnPath to get the path's axis,
then manipulate the certain dot's property with if statement, in my case is it's radius and color.
simple enough...
Can't believe I couldn't figured it out.
I guess I need some sleep now XD
I know it´s not well seen, that you post a link to a code, but I followed this tutorial of making a html drawing canvas app and implemented the source to my wordpress site and everything works fine, except, that all the mouse-click-events seems offset to the left by 100px.
If I open the example html, everything works fine, so I think it has something to do with the parent container css´s or something.
Since I am not very well in js, I thought maybe you can help me figure it out, since I try since a few days now.
This is the tutorial and source code and this is the code of the js file
var drawingApp = (function () {
"use strict";
var canvas,
context,
canvasWidth = 490,
canvasHeight = 220,
colorPurple = "#cb3594",
colorGreen = "#659b41",
colorYellow = "#ffcf33",
colorBrown = "#986928",
outlineImage = new Image(),
crayonImage = new Image(),
markerImage = new Image(),
eraserImage = new Image(),
crayonBackgroundImage = new Image(),
markerBackgroundImage = new Image(),
eraserBackgroundImage = new Image(),
crayonTextureImage = new Image(),
clickX = [],
clickY = [],
clickColor = [],
clickTool = [],
clickSize = [],
clickDrag = [],
paint = false,
curColor = colorPurple,
curTool = "crayon",
curSize = "normal",
mediumStartX = 18,
mediumStartY = 19,
mediumImageWidth = 93,
mediumImageHeight = 46,
drawingAreaX = 111,
drawingAreaY = 11,
drawingAreaWidth = 267,
drawingAreaHeight = 200,
toolHotspotStartY = 23,
toolHotspotHeight = 38,
sizeHotspotStartY = 157,
sizeHotspotHeight = 36,
totalLoadResources = 8,
curLoadResNum = 0,
sizeHotspotWidthObject = {
huge: 39,
large: 25,
normal: 18,
small: 16
},
// Clears the canvas.
clearCanvas = function () {
context.clearRect(0, 0, canvasWidth, canvasHeight);
},
// Redraws the canvas.
redraw = function () {
var locX,
locY,
radius,
i,
selected,
drawCrayon = function (x, y, color, selected) {
context.beginPath();
context.moveTo(x + 41, y + 11);
context.lineTo(x + 41, y + 35);
context.lineTo(x + 29, y + 35);
context.lineTo(x + 29, y + 33);
context.lineTo(x + 11, y + 27);
context.lineTo(x + 11, y + 19);
context.lineTo(x + 29, y + 13);
context.lineTo(x + 29, y + 11);
context.lineTo(x + 41, y + 11);
context.closePath();
context.fillStyle = color;
context.fill();
if (selected) {
context.drawImage(crayonImage, x, y, mediumImageWidth, mediumImageHeight);
} else {
context.drawImage(crayonImage, 0, 0, 59, mediumImageHeight, x, y, 59, mediumImageHeight);
}
},
drawMarker = function (x, y, color, selected) {
context.beginPath();
context.moveTo(x + 10, y + 24);
context.lineTo(x + 10, y + 24);
context.lineTo(x + 22, y + 16);
context.lineTo(x + 22, y + 31);
context.closePath();
context.fillStyle = color;
context.fill();
if (selected) {
context.drawImage(markerImage, x, y, mediumImageWidth, mediumImageHeight);
} else {
context.drawImage(markerImage, 0, 0, 59, mediumImageHeight, x, y, 59, mediumImageHeight);
}
};
// Make sure required resources are loaded before redrawing
if (curLoadResNum < totalLoadResources) {
return;
}
clearCanvas();
if (curTool === "crayon") {
// Draw the crayon tool background
context.drawImage(crayonBackgroundImage, 0, 0, canvasWidth, canvasHeight);
// Draw purple crayon
selected = (curColor === colorPurple);
locX = selected ? 18 : 52;
locY = 19;
drawCrayon(locX, locY, colorPurple, selected);
// Draw green crayon
selected = (curColor === colorGreen);
locX = selected ? 18 : 52;
locY += 46;
drawCrayon(locX, locY, colorGreen, selected);
// Draw yellow crayon
selected = (curColor === colorYellow);
locX = selected ? 18 : 52;
locY += 46;
drawCrayon(locX, locY, colorYellow, selected);
// Draw brown crayon
selected = (curColor === colorBrown);
locX = selected ? 18 : 52;
locY += 46;
drawCrayon(locX, locY, colorBrown, selected);
} else if (curTool === "marker") {
// Draw the marker tool background
context.drawImage(markerBackgroundImage, 0, 0, canvasWidth, canvasHeight);
// Draw purple marker
selected = (curColor === colorPurple);
locX = selected ? 18 : 52;
locY = 19;
drawMarker(locX, locY, colorPurple, selected);
// Draw green marker
selected = (curColor === colorGreen);
locX = selected ? 18 : 52;
locY += 46;
drawMarker(locX, locY, colorGreen, selected);
// Draw yellow marker
selected = (curColor === colorYellow);
locX = selected ? 18 : 52;
locY += 46;
drawMarker(locX, locY, colorYellow, selected);
// Draw brown marker
selected = (curColor === colorBrown);
locX = selected ? 18 : 52;
locY += 46;
drawMarker(locX, locY, colorBrown, selected);
} else if (curTool === "eraser") {
context.drawImage(eraserBackgroundImage, 0, 0, canvasWidth, canvasHeight);
context.drawImage(eraserImage, 18, 19, mediumImageWidth, mediumImageHeight);
}
// Draw line on ruler to indicate size
switch (curSize) {
case "small":
locX = 467;
break;
case "normal":
locX = 450;
break;
case "large":
locX = 428;
break;
case "huge":
locX = 399;
break;
default:
break;
}
locY = 189;
context.beginPath();
context.rect(locX, locY, 2, 12);
context.closePath();
context.fillStyle = '#333333';
context.fill();
// Keep the drawing in the drawing area
context.save();
context.beginPath();
context.rect(drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight);
context.clip();
// For each point drawn
for (i = 0; i < clickX.length; i += 1) {
// Set the drawing radius
switch (clickSize[i]) {
case "small":
radius = 2;
break;
case "normal":
radius = 5;
break;
case "large":
radius = 10;
break;
case "huge":
radius = 20;
break;
default:
break;
}
// Set the drawing path
context.beginPath();
// If dragging then draw a line between the two points
if (clickDrag[i] && i) {
context.moveTo(clickX[i - 1], clickY[i - 1]);
} else {
// The x position is moved over one pixel so a circle even if not dragging
context.moveTo(clickX[i] - 1, clickY[i]);
}
context.lineTo(clickX[i], clickY[i]);
// Set the drawing color
if (clickTool[i] === "eraser") {
//context.globalCompositeOperation = "destination-out"; // To erase instead of draw over with white
context.strokeStyle = 'white';
} else {
//context.globalCompositeOperation = "source-over"; // To erase instead of draw over with white
context.strokeStyle = clickColor[i];
}
context.lineCap = "round";
context.lineJoin = "round";
context.lineWidth = radius;
context.stroke();
}
context.closePath();
//context.globalCompositeOperation = "source-over";// To erase instead of draw over with white
context.restore();
// Overlay a crayon texture (if the current tool is crayon)
if (curTool === "crayon") {
context.globalAlpha = 0.4; // No IE support
context.drawImage(crayonTextureImage, 0, 0, canvasWidth, canvasHeight);
}
context.globalAlpha = 1; // No IE support
// Draw the outline image
context.drawImage(outlineImage, drawingAreaX, drawingAreaY, drawingAreaWidth, drawingAreaHeight);
},
// Adds a point to the drawing array.
// #param x
// #param y
// #param dragging
addClick = function (x, y, dragging) {
clickX.push(x);
clickY.push(y);
clickTool.push(curTool);
clickColor.push(curColor);
clickSize.push(curSize);
clickDrag.push(dragging);
},
// Add mouse and touch event listeners to the canvas
createUserEvents = function () {
var press = function (e) {
// Mouse down location
var sizeHotspotStartX,
mouseX = e.pageX - this.offsetLeft,
mouseY = e.pageY - this.offsetTop;
if (mouseX < drawingAreaX) { // Left of the drawing area
if (mouseX > mediumStartX) {
if (mouseY > mediumStartY && mouseY < mediumStartY + mediumImageHeight) {
curColor = colorPurple;
} else if (mouseY > mediumStartY + mediumImageHeight && mouseY < mediumStartY + mediumImageHeight * 2) {
curColor = colorGreen;
} else if (mouseY > mediumStartY + mediumImageHeight * 2 && mouseY < mediumStartY + mediumImageHeight * 3) {
curColor = colorYellow;
} else if (mouseY > mediumStartY + mediumImageHeight * 3 && mouseY < mediumStartY + mediumImageHeight * 4) {
curColor = colorBrown;
}
}
} else if (mouseX > drawingAreaX + drawingAreaWidth) { // Right of the drawing area
if (mouseY > toolHotspotStartY) {
if (mouseY > sizeHotspotStartY) {
sizeHotspotStartX = drawingAreaX + drawingAreaWidth;
if (mouseY < sizeHotspotStartY + sizeHotspotHeight && mouseX > sizeHotspotStartX) {
if (mouseX < sizeHotspotStartX + sizeHotspotWidthObject.huge) {
curSize = "huge";
} else if (mouseX < sizeHotspotStartX + sizeHotspotWidthObject.large + sizeHotspotWidthObject.huge) {
curSize = "large";
} else if (mouseX < sizeHotspotStartX + sizeHotspotWidthObject.normal + sizeHotspotWidthObject.large + sizeHotspotWidthObject.huge) {
curSize = "normal";
} else if (mouseX < sizeHotspotStartX + sizeHotspotWidthObject.small + sizeHotspotWidthObject.normal + sizeHotspotWidthObject.large + sizeHotspotWidthObject.huge) {
curSize = "small";
}
}
} else {
if (mouseY < toolHotspotStartY + toolHotspotHeight) {
curTool = "crayon";
} else if (mouseY < toolHotspotStartY + toolHotspotHeight * 2) {
curTool = "marker";
} else if (mouseY < toolHotspotStartY + toolHotspotHeight * 3) {
curTool = "eraser";
}
}
}
}
paint = true;
addClick(mouseX, mouseY, false);
redraw();
},
drag = function (e) {
if (paint) {
addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
redraw();
}
// Prevent the whole page from dragging if on mobile
e.preventDefault();
},
release = function () {
paint = false;
redraw();
},
cancel = function () {
paint = false;
};
// Add mouse event listeners to canvas element
canvas.addEventListener("mousedown", press, false);
canvas.addEventListener("mousemove", drag, false);
canvas.addEventListener("mouseup", release);
canvas.addEventListener("mouseout", cancel, false);
// Add touch event listeners to canvas element
canvas.addEventListener("touchstart", press, false);
canvas.addEventListener("touchmove", drag, false);
canvas.addEventListener("touchend", release, false);
canvas.addEventListener("touchcancel", cancel, false);
},
// Calls the redraw function after all neccessary resources are loaded.
resourceLoaded = function () {
curLoadResNum += 1;
if (curLoadResNum === totalLoadResources) {
redraw();
createUserEvents();
}
},
// Creates a canvas element, loads images, adds events, and draws the canvas for the first time.
init = function () {
// Create the canvas (Neccessary for IE because it doesn't know what a canvas element is)
canvas = document.createElement('canvas');
canvas.setAttribute('width', canvasWidth);
canvas.setAttribute('height', canvasHeight);
canvas.setAttribute('id', 'canvas');
document.getElementById('canvasDiv').appendChild(canvas);
if (typeof G_vmlCanvasManager !== "undefined") {
canvas = G_vmlCanvasManager.initElement(canvas);
}
context = canvas.getContext("2d"); // Grab the 2d canvas context
// Note: The above code is a workaround for IE 8 and lower. Otherwise we could have used:
// context = document.getElementById('canvas').getContext("2d");
// Load images
crayonImage.onload = resourceLoaded;
crayonImage.src = cvtemplateDir+ "/images/crayon-outline.png";
markerImage.onload = resourceLoaded;
markerImage.src = cvtemplateDir+ "/images/marker-outline.png";
eraserImage.onload = resourceLoaded;
eraserImage.src = cvtemplateDir+ "/images/eraser-outline.png";
crayonBackgroundImage.onload = resourceLoaded;
crayonBackgroundImage.src = cvtemplateDir+ "/images/crayon-background.png";
markerBackgroundImage.onload = resourceLoaded;
markerBackgroundImage.src = cvtemplateDir+ "/images/marker-background.png";
eraserBackgroundImage.onload = resourceLoaded;
eraserBackgroundImage.src = cvtemplateDir+ "/images/eraser-background.png";
crayonTextureImage.onload = resourceLoaded;
crayonTextureImage.src = cvtemplateDir+ "/images/crayon-texture.png";
outlineImage.onload = resourceLoaded;
outlineImage.src = cvtemplateDir+ "/images/watermelon-duck-outline.png";
};
return {
init: init
};
}());
It´s being implemented on my website here
This is the code to initialize it, which is being called on the hook:
add_action( 'comment_form_before', 'canvas_comments');
function canvas_comments() {
?>
<div id="canvasDiv" style="width:490px;height:220px;"></div>
<script type="text/javascript">
drawingApp.init();
</script>
<?php
}
EDIT:
Just realized in Firefox it´s offsetting even more, I used chrome
Did you try to get offsetTop and offsetLeft explicitly from the canvas?
You are now accessing offsetTop by this in a listener-function. Are you sure that this points to your canvas and not to something else?
I finally fixed with treeno´s suggestion to use canvas.getBoundingClientRect();
I inserted it at the end of the createUserEvents-function like this:
cancel = function () {
......
var rect = canvas.getBoundingClientRect();
// Add mouse event listeners to canvas element
canvas.addEventListener("mousedown", press, false);
.....
},
And finally i replaced every this.OffsetLeft and this.OffsetTop with rect.left and rect.top
Works like a charm!