how to fill canvas rects with image - javascript

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>

Related

Both squares aren't showing up on the canvas

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>

how to get which label was clicked if clicked on label in the canvas graph

I am trying to click at the corner of the polygon and then logging the label which I have clicked.
I am attaching an event listener on canvas clicked and then logging the coordinates but they are not exactly the same which they were while drawing so how to get the intersection point(that is label) on click.
My code so far
export class AppComponent implements AfterViewInit {
coordinates = [
{
x:10,
y:10,
label:'A'
},
{
x:10,
y:250,
label:'B'
},
{
x:250,
y:250,
label:'C'
},
{
x:250,
y:150,
label:'D'
},
{
x:400,
y:150,
label:'E'
},
{
x:400,
y:10,
label:'F'
}
]
/** Template reference to the canvas element */
#ViewChild('canvasEl') canvasRef: ElementRef;
/** Canvas 2d context */
private context: CanvasRenderingContext2D;
constructor() {}
ngAfterViewInit() {
this.setDummyRoofLayout();
}
setDummyRoofLayout() {
let ctx: CanvasRenderingContext2D = this.canvasRef.nativeElement.getContext(
'2d'
);
let ctx2: CanvasRenderingContext2D = this.canvasRef.nativeElement.getContext(
'2d'
);
let label: CanvasRenderingContext2D = this.canvasRef.nativeElement.getContext(
'2d'
);
ctx.strokeStyle = '#EE9723';
ctx.lineWidth = 2;
ctx.beginPath();
ctx2.beginPath();
ctx2.fillStyle = '#EE9723';
ctx2.arc(10, 10, 10, 0, 2 * Math.PI);
ctx2.fill();
ctx2.beginPath();
ctx2.arc(10, 250, 10, 0, 2 * Math.PI);
ctx2.fill();
ctx2.beginPath();
ctx2.arc(250, 250, 10, 0, 2 * Math.PI);
ctx2.fill();
ctx2.beginPath();
ctx2.arc(250, 150, 10, 0, 2 * Math.PI);
ctx2.fill();
ctx2.beginPath();
ctx2.arc(400, 150, 10, 0, 2 * Math.PI);
ctx2.fill();
ctx2.beginPath();
ctx2.arc(400, 10, 10, 0, 2 * Math.PI);
ctx2.fill();
ctx.moveTo(10, 10);
ctx.lineTo(10, 250);
ctx.lineTo(250, 250);
ctx.lineTo(250, 150);
ctx.lineTo(400, 150);
ctx.lineTo(400, 10);
ctx.lineTo(10, 10);
ctx.stroke();
label.beginPath();
label.moveTo(10, 10);
label.fillStyle = 'white';
label.textAlign = 'center';
label.textBaseline = 'middle';
label.font = '.75rem Arial';
label.fillText('A', 10, 10);
label.fillText('B', 10, 250);
label.fillText('C', 250, 250);
label.fillText('D', 250, 150);
label.fillText('E', 400, 150);
label.fillText('F', 400, 10);
label.stroke();
ctx.canvas.addEventListener(
'click',
this.onclick.bind(this)
);
}
onclick(e){
console.log(e);
let xAxis = e.layerX ;
let yAxis = e.layerY;
this.coordinates.forEach(element=>{
if(element.x+4 <xAxis && element.y+4>yAxis){
alert('label A clicked');
}
})
}
}][1]][1]
online editor link
You can do this with a bit of Math:
intersect(point, coord) {
return Math.sqrt((point.x-coord.x) ** 2 + (point.y - coord.y) ** 2) < 10; //where 10 = your circle radius
}
onclick(e: MouseEvent){
const pos = {
x: e.layerX,
y: e.layerY
};
this.coordinates.forEach(coord => {
if (this.intersect(pos, coord)) {
alert('clicked: ' + coord.label);
}
})
}
Stack Blitz Demo

Creating a line animation on canvas

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.

Sorting objects on canvas

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>

Rotating a drawn circle ind Javascript HTML5 Canvas

i have a Canvas:
function drawWindRose(){
var canvas = document.getElementById('windrose');
var bild = canvas.getContext('2d');
var frame = canvas.getContext('2d');
frame.fillStyle = "rgb(200,0,0)";
frame.fillRect (0, 0, 200, 200);
bild.save();
bild.translate(100,100);
bild.rotate((360-Compass)*Math.PI/180);
bild.fillStyle = "rgb(0,0,0)";
bild.font = '8pt Arial';
bild.fillText('N', 102, 30);
bild.fillText('E', 170, 110);
bild.fillText('S', 92, 170);
bild.fillText('W', 30, 96);
bild.closePath()
bild.strokeStyle= "rgb(0,0,0)"; // schwarz
bild.beginPath();
bild.lineWidth = 2;
bild.arc(100,100,95,0,Math.PI*2,true);
bild.moveTo(105,100);
bild.lineTo(195,100);
bild.moveTo(100,105);
bild.lineTo(100,195);
bild.moveTo(95,100);
bild.lineTo(5,100);
bild.moveTo(100,95);
bild.lineTo(100,5);
bild.moveTo(105,100);
bild.arc(100,100,5,0,Math.PI*2,true);
bild.closePath()
bild.stroke();
bild.beginPath();
bild.lineWidth = 5;
if(Azimuth>=0&&Distance>=1)
{
bild.arc(100,100,85,0,Math.PI*2,true);
bild.arc(100,100,85,0,(Azimuth-90)*(Math.PI/180),true);
bild.lineTo(100,100);
}
if(Distance<=1)
{
bild.arc(100,100,2,0,Math.PI*2,true);
}
bild.strokeStyle= "#00FF00";//green
bild.stroke();
bild.translate(-100,-100);
bild.restore();
};
<canvas style="padding-left: 0; padding-right: 0; margin-left: auto; margin-right: auto; display: block;"id="windrose" width="200" height="200"> Ihr Browser kann kein Canvas! </canvas>
Like u can see, i want to rotate the canvas. Its a kind of Compass for a FXOS-App.
I know how to rotate an image, but i dont get it to work with this drawing.
The "Compass" Variable is the Deviceorientation un Degrees.
So if you point the device to east, the Compass must be rotated 90degrees to the left...
Maybe some of you has got an idea.
regards
goerdy
I would use offscreen canvas to draw to the compass and then rotate that as an image onto my main canvas like (Example hardcoded values(azimuth and distance) and get deg from html):
window.onload = setupRose;
var TO_RADIANS = Math.PI / 180;
function drawRotatedImage(context, image, x, y, angle) {
var canvas = document.getElementById('myCanvas');
context.save();
context.translate(x, y);
context.rotate(angle * TO_RADIANS);
context.drawImage(image, -(image.width / 2), -(image.height / 2), image.width, image.height);
context.restore();
}
var myCompass = {};
function setupRose() {
myCompass.g_canvas = document.createElement('canvas');
myCompass.g_canvas.width = 200;
myCompass.g_canvas.height = 200;
m_context = myCompass.g_canvas.getContext('2d');
m_context.fillStyle = "rgb(0,0,0)";
m_context.font = '8pt Arial';
m_context.fillText('N', 102, 30);
m_context.fillText('E', 170, 110);
m_context.fillText('S', 92, 170);
m_context.fillText('W', 30, 96);
m_context.strokeStyle = "rgb(0,0,0)"; // schwarz
m_context.beginPath();
m_context.lineWidth = 2;
m_context.arc(100, 100, 95, 0, Math.PI * 2, true);
m_context.moveTo(105, 100);
m_context.lineTo(195, 100);
m_context.moveTo(100, 105);
m_context.lineTo(100, 195);
m_context.moveTo(95, 100);
m_context.lineTo(5, 100);
m_context.moveTo(100, 95);
m_context.lineTo(100, 5);
m_context.moveTo(105, 100);
m_context.arc(100, 100, 5, 0, Math.PI * 2, true);
m_context.closePath()
m_context.stroke();
m_context.beginPath();
m_context.lineWidth = 5;
if (32 >= 0 && 13 >= 1) {
m_context.arc(100, 100, 85, 0, Math.PI * 2, true);
m_context.arc(100, 100, 85, 0, (32 - 90) * (Math.PI / 180), true);
m_context.lineTo(100, 100);
}
if (13 <= 1) {
m_context.arc(100, 100, 2, 0, Math.PI * 2, true);
}
m_context.strokeStyle = "#00FF00"; //green
m_context.stroke();
}
function drawWindRose() {
var canvas = document.getElementById('windrose');
var bild = canvas.getContext('2d');
var frame = canvas.getContext('2d');
frame.fillStyle = "rgb(200,0,0)";
frame.fillRect(0, 0, 200, 200);
var deg = parseFloat(document.getElementById("degrees").value);
if (!deg) deg = 0;
drawRotatedImage(bild, myCompass.g_canvas, 100, 100, deg);
};

Categories