How to label boxes created on JavaScript canvas? - javascript

I have a canvas where I can draw boxes, and then save the x-y coordinates and width and height of these boxes into JSON format. However, I would like to know if it's possible to perhaps have a field where I can enter a unique name for each one of these objects (eg. bluecar, redcar etc.), in which the name will also appear in the JSON output? As shown in the JSON output below, the coordinates and other information are appearing correctly but I'd like to include names for the objects to differentiate them between the other objects.
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
var canvas2 = document.getElementById("canvas2");
var context2 = canvas2.getContext('2d');
let isDrawing = false;
const annotation = {
x: 0,
y: 0,
w: 0,
h: 0,
printCoordinates: function() {
console.log(`X: ${this.x}px, Y: ${this.y}px, Width: ${this.w}px, Height: ${this.h}px`);
}
};
let boundingBoxes = [];
function handleMouseDown(e) {
start = oMousePos(canvas2, e);
isDrawing = true;
//console.log(start.x, start.y);
canvas2.style.cursor = "crosshair";
}
function handleMouseMove(e) {
if (isDrawing) {
m = oMousePos(canvas2, e);
draw();
}
}
function handleMouseUp(e) {
canvas2.style.cursor = "default";
isDrawing = false;
const box = Object.create(annotation);
box.x = o.x;
box.y = o.y;
box.w = o.w;
box.h = o.h;
boundingBoxes.push(box);
draw();
box.printCoordinates();
console.log(boundingBoxes)
}
canvas2.addEventListener("mousedown", handleMouseDown);
canvas2.addEventListener("mousemove", handleMouseMove);
canvas2.addEventListener("mouseup", handleMouseUp);
function draw() {
o.x = start.x; // start position of x
o.y = start.y; // start position of y
o.w = m.x - start.x; // width
o.h = m.y - start.y; // height
context2.clearRect(0, 0, canvas2.width, canvas2.height); //////***********
// draw all the rectangles saved in the rectsRy
boundingBoxes.map(r => {
drawRect(r)
})
// draw the actual rectangle
drawRect(o);
}
function drawRect(o) {
context2.strokeStyle = "limegreen";
context2.lineWidth = 2;
context2.beginPath(o);
context2.rect(o.x, o.y, o.w, o.h);
context2.stroke();
}
function oMousePos(canvas2, evt) {
let ClientRect = canvas2.getBoundingClientRect();
return {
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
}
document.getElementById('save').addEventListener('click', function() {
// retrieve the canvas data
var canvasContents = canvas.toDataURL(); // a data URL of the current
// canvas
var string = JSON.stringify(boundingBoxes, null, 2);
// create a blob object representing the data as a JSON string
var file = new Blob([string], {
type: 'application/json'
});
// trigger a click event on an <a> tag to open the file explorer
var a = document.createElement('a');
a.href = URL.createObjectURL(file);
a.download = 'data.json';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
Import Image: <input type="file" id="fileUpload" name="fileUpload" multiple/>
<p>
<div id="buttons1">
<button id="reset" onclick="resetcanvas()">Reset Annotations</button> &nbsp
<button id="save">
<span>Export Annotations</span>
</button>
<div id="canvases" align="middle" style="position:relative; width:1580px; height:700px; overflow: scroll; ">
<canvas id="canvas2" align="middle" style="z-index: 1; position: absolute; left: 125px; top: 0px; "></canvas>
<canvas id="canvas" align="middle" style="z-index: 0; position: absolute; left: 125px; top: 0px; "></canvas>
</div>
<p></p>
<br>
<span></span>
</div>
<p></p>
<div id="button ">
</div>
JSON Output:
[
{
"x": 356,
"y": 235,
"w": -105,
"h": -146
},
{
"x": 185,
"y": 238,
"w": -51,
"h": -93
}
]
Any help will be much appreciated, thank you!

I added a few variables to bypass your errors... I assumed that was just a copy/paste error.
On the handleMouseUp you can add a box.name = "Name"; to include a name
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
var canvas2 = document.getElementById("canvas2");
var context2 = canvas2.getContext('2d');
let isDrawing = false;
const annotation = {
x: 0, y: 0, w: 0, h: 0,
printCoordinates: function() {
console.log(`X: ${this.x}px, Y: ${this.y}px, Width: ${this.w}px, Height: ${this.h}px`);
}
};
var o = annotation;
var start;
let boundingBoxes = [];
function handleMouseUp(e) {
canvas2.style.cursor = "default";
isDrawing = false;
const box = Object.create(annotation);
box.x = o.x;
box.y = o.y;
box.w = o.w;
box.h = o.h;
box.name = "Name";
boundingBoxes.push(box);
draw();
box.printCoordinates();
//console.log(boundingBoxes)
}
function handleMouseDown(e) {
start = oMousePos(canvas2, e);
isDrawing = true;
//console.log(start.x, start.y);
canvas2.style.cursor = "crosshair";
}
function handleMouseMove(e) {
if (isDrawing) {
m = oMousePos(canvas2, e);
draw();
}
}
canvas2.addEventListener("mousedown", handleMouseDown);
canvas2.addEventListener("mousemove", handleMouseMove);
canvas2.addEventListener("mouseup", handleMouseUp);
function draw() {
o.x = start.x; // start position of x
o.y = start.y; // start position of y
o.w = m.x - start.x; // width
o.h = m.y - start.y; // height
context2.clearRect(0, 0, canvas2.width, canvas2.height); //////***********
// draw all the rectangles saved in the rectsRy
boundingBoxes.map(r => {
drawRect(r)
})
// draw the actual rectangle
drawRect(o);
}
function drawRect(o) {
context2.strokeStyle = "limegreen";
context2.lineWidth = 2;
context2.beginPath(o);
context2.rect(o.x, o.y, o.w, o.h);
context2.stroke();
}
function oMousePos(canvas2, evt) {
let ClientRect = canvas2.getBoundingClientRect();
return {
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
}
document.getElementById('save').addEventListener('click', function() {
// retrieve the canvas data
var canvasContents = canvas.toDataURL(); // a data URL of the current
// canvas
var string = JSON.stringify(boundingBoxes, null, 2);
// create a blob object representing the data as a JSON string
var file = new Blob([string], {
type: 'application/json'
});
// trigger a click event on an <a> tag to open the file explorer
var a = document.createElement('a');
a.href = URL.createObjectURL(file);
a.download = 'data.json';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
Import Image: <input type="file" id="fileUpload" name="fileUpload" multiple/>
<p>
<div id="buttons1">
<button id="reset" onclick="resetcanvas()">Reset Annotations</button> &nbsp
<button id="save"><span>Export Annotations</span></button>
<div id="canvases" align="middle" style="position:relative; width:1580px; height:700px; overflow: scroll; ">
<canvas id="canvas2" align="middle" style="z-index: 1; position: absolute; left: 125px; top: 0px; "></canvas>
<canvas id="canvas" align="middle" style="z-index: 0; position: absolute; left: 125px; top: 0px; "></canvas>
</div>
<p></p>
<br>
<span></span>
</div>
<p></p>
<div id="button ">
</div>

Related

Is there a way to dynamically draw on a canvas with data from a video in JS?

I have this function that dynamically draws lines(manual graphing) on a canvas with data from a live feed ROI(region of intrest).
<!DOCTYPE html>
<head></head>
<body>
<div class="container" style="display: flex; flex-direction:column">
<div class="row" style="display: flex">
<div class="col-lg-8 offset-lg-2">
<h3 class="mt-5">Live Streaming</h3>
<img id="video" src="{{ url_for('video_feed') }}" width="75%" style="display:none;">
<div class="canvas_container" style="position: relative">
<p id="time" style="position: absolute; margin-top: 40px; margin-left: 10px; color: rgb(141, 238, 178);"></p>
<strong><p id="brightness" style="position: absolute; margin: 10px; color: lightblue;">Brightness: Not Available</p></strong>
<canvas id="canvas1" width="840" height="460" style="position: absolute"></canvas>
<canvas id="canvas2" width="840" height="460"></canvas>
</div>
</div>
<div class="col-lg-4 offset-lg-2">
<h3>ROI</h3>
<canvas id="canvas3" width="840" height="460"></canvas>
</div>
</div>
<div class="row" style="width: 50%;">
<div class="col-lg-4 offset-lg-2">
<h3>Chart</h3>
<canvas id="chart" width="420" height="260"></canvas>
</div>
</div>
</div>
<script>
var video = document.getElementById("video");
var canvas1 = document.getElementById("canvas1");
var canvas2 = document.getElementById("canvas2");
var canvas3 = document.getElementById("canvas3");
var chartCanvas = document.getElementById("chart");
var brightnessDisplay = document.getElementById("brightness");
var ctx = canvas1.getContext("2d");
var ctx2 = canvas2.getContext("2d");
var ctx3 = canvas3.getContext("2d");
var chartContext = chartCanvas.getContext("2d");
setInterval(function() {
ctx2.drawImage(video, 0, 0, canvas2.width, canvas2.height);
}, 33);
var rect = {};
var isDrawing = false;
canvas1.addEventListener('mousedown', function(e) {
var x = e.clientX - canvas1.getBoundingClientRect().left;
var y = e.clientY - canvas1.getBoundingClientRect().top;
rect.startX = x;
rect.startY = y;
isDrawing = true;
});
canvas1.addEventListener('mousemove', function(e) {
if(isDrawing === true) {
ctx.clearRect(0, 0, canvas1.width, canvas1.height);
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY ;
ctx.strokeStyle = "red";
ctx.lineWidth = 3;
ctx.strokeRect(rect.startX, rect.startY, rect.w, rect.h);
}
});
let brightness = 0;
let percentBrightness = 0;
let roi;
chartContext.fillStyle = "#F1F1F1"; // set the background color
chartContext.fillRect(0, 0, chartCanvas.width, chartCanvas.height); // fill the background
chartContext.strokeStyle = "blue";
canvas1.addEventListener('mouseup', function(e) {
isDrawing = false;
// Get the brightness
setInterval(function() {
var imageData = ctx2.getImageData(rect.startX, rect.startY, rect.w, rect.h);
ctx3.clearRect(0, 0, canvas3.width, canvas3.height)
roi = generateGrayscale(imageData);
ctx3.putImageData(roi, 5, 5);
brightness = getBrightness(roi);
percentBrightness = (brightness / 255) * 100;
brightnessDisplay.setHTML("Brightness: " + percentBrightness);
}, 33);
});
function drawLines() {
// let data = [100, 150, 200, 175, 125, 50, 25, 75, brightness];
let data = roi?.data;
chartContext.clearRect(0, 0, chartCanvas.width, chartCanvas.height);
for (let i = 0; i < data?.length; i+=4) {
const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
chartContext.beginPath();
chartContext.moveTo(i * (chartCanvas.width / roi.width), chartCanvas.height);
chartContext.lineTo(i * (chartCanvas.width / roi.width), chartCanvas.height - avg);
chartContext.stroke();
}
// requestAnimationFrame(() => drawLines(data));
setTimeout(() => {
requestAnimationFrame(() => drawLines(data));
}, 1000 / 30);
}
requestAnimationFrame(drawLines);
function generateGrayscale(imageData) {
var pixels = imageData.data;
for (var i = 0; i < pixels.length; i+=4){
const gray = (pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3;
pixels[i] = gray;
pixels[i + 1] = gray;
pixels[i + 2] = gray;
}
return imageData;
}
function getBrightness(imageData) {
var pixels = imageData.data;
var brightness = 0;
for (var i = 0; i < pixels.length; i+=4) {
brightness += pixels[i];
}
// Divide by the total number of pixels to obtain the average grayscale value
brightness = brightness / (pixels.length / 4);
return brightness
}
// For date display
setInterval(function(){
var currentDate = new Date();
var dateString = currentDate.toLocaleDateString();
var timeString = currentDate.toLocaleTimeString();
var fullString = dateString + " " + timeString;
document.getElementById("time").innerHTML = fullString;
}, 1000);
</script>
<style>
#canvas_container { position: relative; }
.canvas1 { position: absolute; top: 0; left: 0; }
.canvas2 { position: absolute; top: 0; left: 0; }
</style>
</body>
</html>
this does work but after some time(seconds) the live feed freezes and thus the roi remains the same. This happens as the data gets larger and larger which is expected but I'm wondering if there's a way to achieve this without killing the CPU? In python I would maybe move this to a different thread but I don't think JS would support this.
Any suggestions are welcomed.
Sample output of what I have

Movable selection on a canvas

Here below is how to draw a "selection rectangle" on a <canvas> with drag-and-drop, see How to draw a selection rectangle with drag and drop on a HTML canvas?.
Is there a simple way to detect the selection rectangle on hover at a distance of a few pixels, and allow to move the selection rectangle with drag-and-drop?
var c1 = document.getElementById("c1"), c2 = document.getElementById("c2");
var ctx1 = c1.getContext("2d"), ctx2 = c2.getContext("2d");
ctx2.setLineDash([5, 5]);
var origin = null;
window.onload = () => { ctx1.drawImage(document.getElementById("img"), 0, 0); }
c2.onmousedown = e => { origin = {x: e.offsetX, y: e.offsetY}; };
window.onmouseup = e => { origin = null; };
c2.onmousemove = e => {
if (!!origin) {
ctx2.strokeStyle = "#ff0000";
ctx2.clearRect(0, 0, c2.width, c2.height);
ctx2.beginPath();
ctx2.rect(origin.x, origin.y, e.offsetX - origin.x, e.offsetY - origin.y);
ctx2.stroke();
}
};
#img { display: none; }
#canvas-container { position: relative; }
canvas { position: absolute; left: 0; top: 0; }
#c1 { z-index: 0; }
#c2 { z-index: 1; }
<img id="img" src="https://i.imgur.com/okSIKkW.jpg">
<div id="canvas-container">
<canvas id="c1" height="200" width="200"></canvas>
<canvas id="c2" height="200" width="200"></canvas>
</div>
Storing the current selection
To be able to move an existing selection, you have to save its state. Right now, your code "forgets" about it after drawing it once.
You can save your selection in a variable on mouseup like so:
const dx = origin.x - mouse.x;
const dy = origin.y - mouse.y;
selection = {
left: Math.min(mouse.x, origin.x),
top: Math.min(mouse.y, origin.y),
width: Math.abs(dx),
height: Math.abs(dy)
}
Intersection check
Your selection is a rectangle. You can check whether the mouse is intersecting the rectangle like so:
const intersects = (
mouse.x >= selection.left &&
mouse.x <= selection.left + selection.width &&
mouse.y >= selection.top &&
mouse.y <= selection.top + selection.height
);
If you want to add some padding around the rectangle, you can change the checks to be, for example, mouse.x >= selection.left - PADDING.
Make or Move
You now have to support 2 types of interactions:
Making new selections, and
Moving existing selections
This is where my implementation gets a bit messy, but you can probably refactor it yourself 🙂
I didn't change much in the making-selections code, other than saving the selection to a variable.
When moving selections, you take the dx and dy of your mouse drag and add them to the selection's original position (ox, oy):
const dx = origin.x - mouse.x;
const dy = origin.y - mouse.y;
selection.left = ox - dx;
selection.top = oy - dy;
Here's everything in a runnable snippet:
var c1 = document.getElementById("c1"),
c2 = document.getElementById("c2");
var ctx1 = c1.getContext("2d"),
ctx2 = c2.getContext("2d");
ctx2.setLineDash([5, 5]);
var origin = null;
let selection = null;
let selectionHovered = false;
let interaction = null;
let ox = null;
let oy = null;
window.onload = () => { ctx1.drawImage(document.getElementById("img"), 0, 0); }
c2.onmousedown = e => {
origin = {x: e.offsetX, y: e.offsetY};
if (selectionHovered) {
interaction = "MOVE_SELECTION";
ox = selection.left;
oy = selection.top;
} else {
interaction = "MAKE_SELECTION";
}
};
window.onmouseup = e => {
interaction = null;
origin = null;
};
c2.onmousemove = e => {
const x = e.offsetX;
const y = e.offsetY;
if (!interaction) {
selectionHovered = (
selection &&
x >= selection.left &&
x <= selection.left + selection.width &&
y >= selection.top &&
y <= selection.top + selection.height
);
} else {
const dx = origin.x - x;
const dy = origin.y - y;
// Update
switch (interaction) {
case "MOVE_SELECTION":
selection.left = ox - dx;
selection.top = oy - dy;
break;
case "MAKE_SELECTION":
selection = {
left: Math.min(x, origin.x),
top: Math.min(y, origin.y),
width: Math.abs(dx),
height: Math.abs(dy)
}
break
default:
// Do nothing
}
// Set selectionHovered
if (selection) {
} else {
selectionHovered = false;
}
}
// Draw
if (selection) drawSelection(selection);
};
function drawSelection({ top, left, width, height }) {
// Draw rect
ctx2.strokeStyle = "#ff0000";
ctx2.clearRect(0, 0, c2.width, c2.height);
ctx2.beginPath();
ctx2.rect(left, top, width, height);
ctx2.stroke();
// Set mouse
c2.style.cursor = selectionHovered ? "move" : "default";
}
#img { display: none; }
body { margin: 0; }
#canvas-container { position: relative; }
canvas { position: absolute; left: 0; top: 0; }
#c1 { z-index: 0; }
#c2 { z-index: 1; }
<img id="img" src="https://i.imgur.com/okSIKkW.jpg">
<div id="canvas-container">
<canvas id="c1" height="200" width="200"></canvas>
<canvas id="c2" height="200" width="200"></canvas>
</div>

Can I snap this (blue) div on the highlighted square on the canvas?

When you drag the blue div, I'd like it to 'snap' into the middle of the green highlighted square when the mouse button is released. I cannot seem to find a way to read the coordinates from the box[] (Path2D()) interface. So is there a simple way to achieve this? Should I save the coordinates of the squares individually? Or can I somehow still get the points out of the Path2D interface?
const board = document.getElementById("board");
const ctxB = board.getContext("2d");
var Grid = false;
const boxsize = 64;
const amountOfrows = 8;
const amountOfHorBoxes = 7;
const totalAmountOfBoxes = amountOfrows * amountOfHorBoxes;
board.width = boxsize * 7.5;
board.height = boxsize * 8;
var addHorBox = 0;
var addVertBox = 0;
let boxes = [];
function drawGrid(){
Grid=true;
// for the amout of rows
for (let rowcount = 0; rowcount < amountOfrows; rowcount++) {
ctxB.lineWidth = 1;
ctxB.strokeStyle = "black";
ctxB.fillStyle = "white";
// filling the rows
if(rowcount%2==0){
for (let boxcount = 0; boxcount < amountOfHorBoxes; boxcount++) {
let box = new Path2D();
box.rect(addHorBox, addVertBox, boxsize, boxsize);
boxes.push(box);
ctxB.fill(box);
ctxB.stroke(box);
addHorBox+=boxsize;
}
}
addHorBox=0;
addVertBox+=boxsize;
}
}
MoveUnit(document.getElementById("unit"));
function MoveUnit(unit){
const rect = board.getBoundingClientRect();
const checkX = unit.clientWidth/2 - rect.left;
const checkY = unit.clientHeight/2 - rect.top;
var initialX;
var initialY;
var tile;
unit.onmousedown = mouseDown;
function mouseDown(e){
e = e || window.event;
e.preventDefault();
initialX = e.clientX;
initialY = e.clientY;
document.onmouseup = mouseUp;
document.onmousemove = moveMouse;
}
function moveMouse(e){
e = e || window.event;
e.preventDefault();
unit.style.top = (unit.offsetTop + e.clientY - initialY) + "px";
unit.style.left = (unit.offsetLeft + e.clientX - initialX) + "px";
boxes.forEach(box => {
if (ctxB.isPointInPath(box, unit.offsetLeft + checkX, unit.offsetTop + checkY)) {
ctxB.lineWidth = 2;
ctxB.fillStyle = 'green';
ctxB.fill(box);
ctxB.stroke(box);
tile=box;
}else{
ctxB.lineWidth = 1;
ctxB.strokeStyle = "black";
ctxB.fillStyle = 'white';
ctxB.fill(box);
ctxB.stroke(box);
}
});
// saving new mousepos after moving the unit
initialX = e.clientX;
initialY = e.clientY;
}
function mouseUp(){
document.onmousemove = false;
}
}
function loop(timestamp){
// draw once
if(Grid==false) drawGrid();
requestAnimationFrame(loop);
}
loop();
#board{
background-color: #999;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
#unit{
background-color: rgb(134, 162, 224);
position: absolute;
cursor: pointer;
z-index: 1;
width: 30px;
height: 30px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="testing.css"/>
<title>Gridding</title>
</head>
<body>
<div id="unit"></div>
<canvas id="board"></canvas></div>
<script src="testing.js"></script>
</body>
</html>
In those Path2D instances we can add some useful data that can do what you need:
let box = new Path2D();
box.rect(...
box.data = { row, column }
then on the function mouseUp we use that to 'snap' into the middle
unit.style.top = ((box.data.column + 0.5) * boxsize) + "px";
unit.style.left = ((box.data.row + 0.5) * boxsize) + "px";
I reduced a lot of your code on my example below, I'm focusing just on the question, you should do the same when asking questions, that helps others get to the point faster and gives you a better chance of a quick answer.
const board = document.getElementById("board");
const ctxB = board.getContext("2d");
const unit = document.getElementById("unit");
const boxsize = 32;
board.width = board.height = boxsize * 4;
let boxes = [];
for (let r = 0; r < 4; r++) {
for (let c = 0; c < 4; c++) {
let box = new Path2D();
box.rect(r * boxsize, c * boxsize, boxsize -0.5, boxsize -0.5);
box.data = { r, c }
boxes.push(box);
}
}
var position = { x: -1, y: -1 }
function mouseDown(e) {
document.onmouseup = mouseUp;
document.onmousemove = moveMouse;
position = { x: e.clientX, y: e.clientY}
}
function mouseUp() {
document.onmousemove = false;
boxes.forEach(box => {
if (ctxB.isPointInPath(box, position.x, position.y)) {
unit.style.top = ((box.data.c + 0.5) * boxsize) + "px";
unit.style.left = ((box.data.r + 0.5) * boxsize) + "px";
}
});
}
function moveMouse(e) {
unit.style.top = (unit.offsetTop + e.clientY - position.y) + "px";
unit.style.left = (unit.offsetLeft + e.clientX - position.x) + "px";
position = { x: e.clientX, y: e.clientY}
}
function loop(timestamp) {
ctxB.clearRect(0, 0, board.width, board.height)
boxes.forEach(box => {
ctxB.fillStyle = ctxB.isPointInPath(box, position.x, position.y)? 'green' : 'white'
ctxB.fill(box);
ctxB.stroke(box);
});
requestAnimationFrame(loop);
}
loop();
unit.onmousedown = mouseDown;
#unit {
background-color: blue;
position: absolute;
width: 20px;
height: 20px;
}
<canvas id="board"></canvas>
<br>
<div id="unit"></div>
In my code I'm separating the mouse events from the drawing,
we draw only on the loop.
the events change state variables.
Also noticed that in some cases two boxes got highlighted at the same time changing the size of the rect by a tiny bit fixed that boxsize -0.5

Draw in several HTML CANVAS (at the same time) with the same mouse output

Maybe this a stupid question but I can't figure out what is going on. I'm studying digital drawing with HTML CANVAS and I want to draw within several CANVAS (at the same time) with the same mouse movement output. I made a function to handle the context (ctx) of each CANVAS when drawing(ctx, xpos, ypos, bool). But every time I try to use it, it just draw in one of them.
I made an exemple here
https://jsfiddle.net/rboyart/Lgzwry02/1/
(If you click and move in the white space, it should draw in both CANVAS)
<style>
html, body {height: 100%}
.full-height {height: 100%}
canvas {background-color:#ddd; z-index:-1; float: left; margin-right:10px}
.objectBox {z-index: 0; position: relative; top:0; left:0 }
</style>
<canvas id="canvas1" width="200" height="200" ></canvas>
<canvas id="canvas2" width="200" height="200" ></canvas>
<div id="objectBox" class="full-height" style="width:100%; height:100%; background-color:transparent;">
</div>
<script type="text/javascript"> var canvas1 = document.getElementById('canvas1'); var ctxPaint = canvas1.getContext('2d'); var canvas2 = document.getElementById('canvas2'); var ctxPaint2 = canvas2.getContext('2d'); var isDrawing, lastPoint; function drawing(ctx, xpos, ypos, bool) { if(!bool){ lastPoint = { x: xpos, y: ypos } } if(bool) { ctx.lineJoin = "round"; ctx.lineCap = "butt"; ctx.strokeStyle = "#000000"; ctx.globalAlpha = "1"; ctx.globalCompositeOperation = "source-over"; if(ctx.lineWidth >= 5) { ctx.lineWidth -= 0.1; } var currentPoint = { x: xpos, y: ypos }; ctx.beginPath(); ctx.moveTo(lastPoint.x, lastPoint.y); ctx.lineTo(currentPoint.x, currentPoint.y); ctx.closePath(); ctx.stroke(); lastPoint = currentPoint; } } /*END FUNCTION DRAWING */ function findObjectCoords(mouseEvent) { var obj = document.getElementById("objectBox"); var widthOBJ = obj.clientWidth; var heightOBJ = obj.clientHeight; var obj_left = 0; var obj_top = 0; var xpos; var ypos; while (obj.offsetParent) { obj_left += obj.offsetLeft; obj_top += obj.offsetTop; obj = obj.offsetParent; } obj.onmousedown = function(e) { isDrawing = true; }; obj.onmouseup = function() { isDrawing = false; }; if (mouseEvent) { xpos = mouseEvent.pageX; ypos = mouseEvent.pageY; } else { xpos = window.event.x + document.body.scrollLeft - 2; ypos = window.event.y + document.body.scrollTop - 2; } xpos -= obj_left; ypos -= obj_top; var numX = map_range(xpos, 0, widthOBJ, 0, 200); var numY = map_range(ypos,0, heightOBJ, 0, 200); drawing(ctxPaint, parseInt(numX), parseInt(numY), isDrawing); drawing(ctxPaint2, parseInt(numX), parseInt(numY), isDrawing); } document.getElementById("objectBox").onmousemove = findObjectCoords; function map_range(value, low1, high1, low2, high2) { return low2 + (high2 - low2) * (value - low1) / (high1 - low1); } </script>
It's because of your lastPoint variable which you use for both canvases. When you call drawing the first time lastpoint is overwritten. So for calling drawing the 2nd time your lastPoint is already the current point => no point is drawing.
To fix this you can use 2 separate lastPoint variables or update lastPoint only the second time you call drawing like I did here: https://jsfiddle.net/ay45sx19/

Canvas spritesheet and touch event is not working when I change position to absolute?

I am developing simple game with HTML5 Canvas. I used sprite image for animate, when I change position to absolute its not working and also touchevents are not working on canvas object, if change position to absolute then touchevents works fine but sprite stuff not works.
What might be the problem. Here is my JavaScript code.
Here is my whole code
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="js/jquery_v1.9.1.js"></script>
<script type="text/javascript">
var canvas = null;
var img = null;
var ctx = null;
var antX = 0,
antY = 0;
var canvasX = 0,
canvasY = 0;
var imageReady = false;
var img;
function onload() {
canvas = document.getElementById("gameCanvas");
ctx = canvas.getContext("2d");
img = document.getElementById("bg");
img.onload = loaded();
resize();
canvas.addEventListener("touchstart", doTouchStart, false);
document.addEventListener("click", function (e) {
if (!e) var e = e;
// e2.preventDefault();
canvasX = e.pageX - canvas.offsetLeft;
console.log("[mouseXY event] CanX array :" + canvasX);
canvasY = e.pageY - canvas.offsetTop;
console.log("[mouseXY event] CanY array:" + canvasY);
//alert("X :"+canvasX+"Y :"+canvasY);
antX = canvas.width / 2 - 48;
antY = canvas.height / 2 - 48;
//alert("X :"+antX+"Y :"+antY);
if (canvasX >= antX - 40 && canvasX <= antX + 40) {
// Is touchY between (antY - 10) and (antY + 10)?
if (canvasY >= antY - 40 && canvasY <= antY + 40) {
// The user touched the ant
alert("Touched on image");
}
}
});
}
function doTouchStart() {
alert("T");
}
function select_element() {
var offset = $div.offset();
var x = ev.clientX - offset.left;
var y = ev.clientY - offset.top;
alert("X :" + x + "Y :" + y);
}
function loaded() {
/* document.getElementById('divId').style.width = canvas.width / 2 - 48;
document.getElementById('divId').style.height = canvas.height / 2 - 48;
document.getElementById('divId').style.zIndex = "999"; */
//document.getElementById('divId');
imageReady = true;
setTimeout(update, 1000 / 60);
}
function resize() {
canvas.width = canvas.parentNode.clientWidth;
canvas.height = canvas.parentNode.clientHeight;
redraw();
}
function redraw() {
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
if (imageReady) {
ctx.drawImage(
img,
frame * 192,
0,
192,
192,
canvas.width / 2 - 48,
canvas.height / 2 - 48,
192,
192
);
}
}
var frame = 0;
function update() {
//console.log('hi');
redraw();
frame++;
if (frame >= 2) frame = 0;
setTimeout(update, 1000 / 10);
}
</script>
</head>
<body
onresize="onresize()"
onload="onload()"
style="position: absolute; padding: 0; margin: 0; height: 100%; width: 100%"
>
<img
class="clickable"
alt="simple1"
id="bg"
src="img/blink.png"
style="position: absolute; display: none; z-index: 1"
/>
<canvas id="gameCanvas" style="position: absolute"></canvas>
</body>
</html>
Any help would be much appreciated.
Does it work if you try:
<canvas id="can" style="position:absolute; z-index:999;">

Categories