I draw two bottons using a rectangle with text over top.
As you can see I get two different results using the same loop.
The first "button" has the text hidden behind the box.
The second has the text written on top.
Why is this? How does sorting work in canvas?
<body>
<canvas id="canvas" width="320" height="512"
style="position: absolute; left: 500px; top: 50px; z-index: 1;"></canvas>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext("2d");
canvas.style.backgroundColor = 'rgba(0, 0, 0, 0)';
context.clearRect(0, 0, 320, 16);
gameMenu();
function gameMenu(){
var buttons = [ {x: 210, y: 420, w: 80, h: 30, s: "Messages"},
{x: 210, y: 470, w: 80, h: 30, s: "Pause"} ], i = 0, r;
while(r = buttons[i++]) {
context.rect(r.x, r.y, r.w, r.h);
context.fillStyle = "rgb(26,26,26)";
context.fill();
context.fillStyle = 'White';
context.font = "16px Tahoma";
context.fillText(r.s, r.x + 18, r.y + 22);
}
}
</script>
</body>
Here is a JS Fiddle:
https://jsfiddle.net/oa84Lsxn/1/
You must begin each new path operation (==each new .rect) with context.beginPath. Otherwise all previous .rects will be redrawn along with the current .rect.
Your issue is that all previous paths are redrawn along with the new path. This means your first rect is being redrawn along with your new second rect -- causing the first rect's text to be overwritten by the first rect.
Here's a working version your code with context.beginPath added.
var canvas=document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.style.backgroundColor = 'rgba(0, 0, 0, 0)';
context.clearRect(0, 0, 320, 16);
gameMenu();
function gameMenu(){
// x,y changed to fit demo on StackSnipped window
var buttons = [ {x: 40, y: 20, w: 80, h: 30, s: "Messages"},
{x: 40, y: 70, w: 80, h: 30, s: "Pause"} ],
i = 0, r;
while(r = buttons[i++]) {
context.beginPath();
context.rect(r.x, r.y, r.w, r.h);
context.fillStyle = "rgb(26,26,26)";
context.fill();
context.fillStyle = 'White';
context.font = "16px Tahoma";
context.fillText(r.s, r.x + 18, r.y + 22);
}
}
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>
Related
This is my code:
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
function draw() {
context.fillStyle = "rgb(200, 0, 0)";
context.fillRect(50, 50, 0, 0);
};
draw();
When I run it, I get no errors but it doesn't add the squares to the canvas. Can someone tell me why this happens and how to fix it?
Your second Rectangle does not have a height and width.
the function has the parameters x, y, width, height -> fillRect(x, y, width, height).
Your line context.fillRect(50, 50, 0, 0); creates a box with width and height of 0 at 50px from x and y.
const c = document.getElementById("myCanvas");
const ctx = c.getContext("2d");
const settings = {x: 50, y: 50, height: 50, width: 50};
function draw() {
if (ctx) {
ctx.fillStyle = "rgb(0, 200, 0)";
ctx.fillRect(settings.x, settings.y, settings.width, settings.height);
ctx.fillStyle = "rgb(200, 0, 0)";
ctx.fillRect(0, 0, 50, 50);
};
};
draw();
<canvas id="myCanvas"></canvas>
I'm trying to draw multiple strokes on a canvas and I'd like them to have a common shadow. Currently the cast shadows on one another which is not what I want.
Ideal result
What I've tried
Creating shadow using ctx.shadowColor jsfiddle
Creating shadow using ctx.filter jsfiddle
Creating shadow using css box-shadow on the canvas -- draws shadow on the whole box
Creating shadow using css filter on the canvas -- draws shadow on the whole box
You can use Path2D and add all your segments to one path, then do the stroke to that path.
Here is your jsfiddle using ctx.filter with my recommendation.
const segments = [
[{x: 10, y: 50}, {x: 50, y: 50}],
[{x: 50, y: 10}, {x: 50, y: 50}],
[{x: 90, y: 50}, {x: 50, y: 50}],
[{x: 50, y: 90}, {x: 50, y: 50}],
]
let path = new Path2D()
segments.forEach(segment => {
path.moveTo(segment[0].x, segment[0].y)
path.lineTo(segment[1].x, segment[1].y)
})
const ctx = document.getElementById('my-canvas').getContext('2d')
ctx.lineWidth = 5
ctx.filter = 'drop-shadow(-3px -3px 3px #f00)';
ctx.strokeStyle = 'black'
ctx.stroke(path)
<canvas width="100" height="100" id="my-canvas" style="background: #00ff00"/>
You can read more about Path2D here:
https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D
If you need each stroke to be independent (i.e so that they have each their own strokeStyle or lineWidth), you will need to use a second detached canvas:
on this detached canvas you draw all your strokes without shadow
you drawImage that detached canvas on the visible one with the shadow:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const detached = canvas.cloneNode();
const detachedCtx = detached.getContext("2d");
const colors = ["green", "blue", "yellow", "orange", "aqua"];
detachedCtx.lineWidth = 5;
for (let color of colors) {
// draw on the detached canvas
detachedCtx.beginPath();
for (let i = 0; i<5; i++) {
detachedCtx.lineTo(Math.random() * canvas.width, Math.random() * canvas.height);
}
detachedCtx.strokeStyle = color;
detachedCtx.lineWidth = Math.random() * 8 + 2;
detachedCtx.stroke();
}
// now draw all this with shadows on the visible canvas
ctx.shadowOffsetX = 3;
ctx.shadowOffsetY = 3;
ctx.shadowBlur = 3;
ctx.shadowColor = "red";
ctx.drawImage(detached, 0, 0);
<canvas></canvas>
But to produce the image you have all you need is to call stroke() only once after you did compose your full path:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "#0F0";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.lineWidth = 5;
ctx.shadowOffsetX = -3;
ctx.shadowOffsetY = -3;
ctx.shadowBlur = 3;
ctx.shadowColor = "red";
ctx.moveTo(10, 50);
ctx.lineTo(90, 50);
ctx.moveTo(50, 10);
ctx.lineTo(50, 90);
ctx.stroke(); // stroke only once, with the full path being traced
<canvas width=100 height=100></canvas>
I created a canvas for example with 4 cells , how can i set an image to each cell ?
my Canvas rotated and i don't want to my images rotate too , also when mouse move on cells, images gone!
my code :
<html>
<head>
<script src="jquery-3.4.1.js"></script>
</head>
<body bgcolor="black">
<canvas id="tutorial" width="500" height="500"></canvas>
<script type="text/javascript">
var canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d"),
rects = [
{x: 0, y: 0, w: 100, h: 100},
{x: 0, y: 100, w: 100, h: 100},
{x: 100, y: 100, w: 100, h: 100},
{x: 100, y: 0, w: 100, h: 100}
], i = 0, r;
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.scale(0.71, 0.3834);
ctx.rotate(-0.25 * Math.PI);
// render initial rects.
while(r = rects[i++]) ctx.rect(r.x, r.y, r.w, r.h);
// var img = new Image();
// img.onload = function () {
// ctx.drawImage(img, 0, 0);
// }
// img.src = "i1.png";
ctx.fillStyle = "#c5de89";
ctx.fill();
canvas.onmousemove = function(e) {
var rect = this.getBoundingClientRect(),
x = e.clientX - rect.left,
y = e.clientY - rect.top,
i = 0, r;
ctx.clearRect(0, 0, canvas.width, canvas.height);
while(r = rects[i++]) {
ctx.beginPath();
ctx.rect(r.x, r.y, r.w, r.h);
ctx.fillStyle = ctx.isPointInPath(x, y) ? "red" : "#c5de89";
ctx.fill();
}
};
</script>
</body>
</html>
I want somthing like this :
My Canvas :
You should add image x and y cordinate inside the onmousemove function too since you are rebuilding the canvas in that function.
var angle = 0;
var canvas = document.getElementById("tutorial"),
ctx = canvas.getContext("2d"),
rects = [{
x: 0,
y: 0,
w: 100,
h: 100
},
{
x: 0,
y: 100,
w: 100,
h: 100
},
{
x: 100,
y: 100,
w: 100,
h: 100
},
{
x: 100,
y: 0,
w: 100,
h: 100
}
],
i = 0,
r;
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.scale(0.71, 0.3834);
ctx.rotate(-0.25 * Math.PI);
// render initial rects.
while (r = rects[i++]) {
ctx.rect(r.x, r.y, r.w, r.h);
ctx.fillStyle = "#c5de89";
ctx.fill();
ctx.save();
ctx.rotate(0.25 * Math.PI);
base_image = new Image();
base_image.src = 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png';
ctx.drawImage(base_image, r.x, r.y - 75);
ctx.restore()
}
canvas.onmousemove = function(e) {
var rect = this.getBoundingClientRect(),
x = e.clientX - rect.left,
y = e.clientY - rect.top,
i = 0,
r;
ctx.clearRect(0, 0, canvas.width, canvas.height);
while (r = rects[i++]) {
ctx.beginPath();
ctx.rect(r.x, r.y, r.w, r.h);
ctx.fillStyle = ctx.isPointInPath(x, y) ? "red" : "#c5de89";
ctx.fill();
ctx.save();
ctx.rotate(0.25 * Math.PI);
base_image = new Image();
base_image.src = 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png';
ctx.drawImage(base_image, r.x, r.y - 100);
ctx.restore()
}
};
<html>
<head>
<script src="jquery-3.4.1.js"></script>
</head>
<body bgcolor="black">
<canvas id="tutorial" width="500" height="500"></canvas>
</body>
</html>
I'm a newbie in canvas drawing. I want to draw the PV string model and the direction of flow of electrons into <canvas> tag.
This is what I want to achieve, redrawing the lines from the following direction:
How do I initially set the animation location, and do I need to update it via setTimeout?
Here is what I try so far:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
// drawing code here
/* First Row */
ctx.fillStyle = "rgb(2,150,224, 1)";
ctx.fillRect(50, 50, 50, 50);
ctx.fillStyle = "rgb(2,150,224, 1)";
ctx.fillRect(110, 50, 50, 50);
ctx.fillStyle = "rgb(188,12,50, 1)";
ctx.fillRect(170, 50, 50, 50);
ctx.fillStyle = "rgb(2,150,224, 1)";
ctx.fillRect(230, 50, 50, 50);
ctx.fillStyle = "rgb(2,150,224, 1)";
ctx.fillRect(290, 50, 50, 50);
/* Second Row */
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(50, 150, 50, 50);
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(110, 150, 50, 50);
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(170, 150, 50, 50);
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(230, 150, 50, 50);
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(290, 150, 50, 50);
/* Paths */
ctx.beginPath();
ctx.lineWidth = "3";
ctx.strokeStyle = "rgb(34,177,76, 1)";
ctx.moveTo(0, 75);
ctx.lineTo(400, 75);
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = "10";
ctx.strokeStyle = "rgb(34,177,76, 1)";
ctx.moveTo(400, 75);
ctx.lineTo(400, 175);
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = "3";
ctx.strokeStyle = "rgb(34,177,76, 1)";
ctx.moveTo(0, 175);
ctx.lineTo(400, 175);
ctx.stroke();
} else {
// canvas-unsupported code here
}
/* canvas {
border: 1px solid #d3d3d3;
} */
<canvas id="myCanvas" width="400" height="400">
Your browser does not support the HTML5 canvas tag.</canvas>
Any help would be appreciated!
There are many ways to animate this; here's my approach (excerpt; see
JSFiddle for full code):
var lerp = (a, b, t) => a + t * (b - a);
var speed = 0.01;
var time = 0;
var visited = [];
var points = [
{
from: { x: 0, y: 75 },
to: { x: 395, y: 75 }
},
{
from: { x: 395, y: 75 },
to: { x: 395, y: 175 }
},
{
from: { x: 395, y: 175 },
to: { x: 0, y: 175 }
}
];
/* Paths */
ctx.lineWidth = 3;
ctx.strokeStyle = "rgb(34, 177, 76, 1)";
(function update() {
if (points.length) {
visited.push({
x: lerp(points[0].from.x, points[0].to.x, time),
y: lerp(points[0].from.y, points[0].to.y, time)
});
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBoxes(ctx);
ctx.beginPath();
ctx.moveTo(visited[0].x, visited[0].y)
visited.forEach(e => ctx.lineTo(e.x, e.y));
ctx.stroke();
time += speed;
if (time >= 1) {
time = 0;
points.shift();
}
requestAnimationFrame(update);
}
})();
The idea is to keep a data structure of all the turning points, then lerp along the path, drawing a line along the way. Use an easing function instead of lerp if you prefer a more "modern"-looking animation; easing is usually easier to implement and may result in removal of some code (for example, no need to keep track of starting points and time).
Last minor note--your original code was cutting off the line at the right edge of the canvas, so I took the liberty of using 395 instead of 400 for the drawing width.
I'm trying to split image in my canvas.
First I'm declaring canvas in HTML:
<canvas width="600" height="400" id="canvas_1">
Canvas tag not supported
</canvas>
Then I'm unsuccesfully spliting my image:
var canvas = document.getElementById("canvas_1");
if (canvas.getContext){
var canvas_context = canvas.getContext("2d");
var img = document.getElementById("london_eye");
canvas_context.drawImage(img, 0, 0, 230, 300, 20, 20, 80, 300);
canvas_context.drawImage(img, 30, 0, 180, 300, 200, 20, 80, 300);
}
I guess I'm missing something there..
canvas_context.drawImage(img, 0, 0, 230, 300, 20, 20, 80, 300);
canvas_context.drawImage(img, 30, 0, 180, 300, 200, 20, 80, 300);
FIDDLE
Thank you for your time and advices
Original Code
var canvas = document.getElementById("canvas_1");
if (canvas.getContext){
var canvas_context = canvas.getContext("2d");
var img = document.getElementById("london_eye");
canvas_context.drawImage(img, 0, 0, 60, 120, 0, 0, 60, 120);
canvas_context.drawImage(img, 60, 0, 60, 120, 70, 0, 60, 120);
}
The last four parameters are destX, destY, destWidth, destHeight. So this is where on the canvas you want to put these pieces, you can see second piece is at 70 so its width of first piece 60 plus gap of 10.
I put a gap of 10px to show the two pieces of your img in the snippet!
var i = new Image();
i.crossOrigin = '';
i.onload = function() {
var canvas = document.getElementById("canvas_1");
if (canvas.getContext){
var canvas_context = canvas.getContext("2d");
canvas_context.drawImage(i, 0, 0, 60, 120, 0, 0, 60, 120);
canvas_context.drawImage(i, 60, 0, 60, 120, 70, 0, 60, 120);
}
};
i.onerror = function() {
i.src = 'http://cors.io?u=' + i.src;
i.onerror = function() {
document.write('Error loading image');
}
};
i.src = 'https://i.stack.imgur.com/olfBw.png';
<canvas id="canvas_1"></canvas>