(HTML5 Canvas) Fillstyle img doesnt move with my terrain path - javascript

I´m writting a canvas game. I have some random produced terrain made with lineTo(), closePath() and filled out with an img as fillStyle. So far so good. But when i move the terrain with js the img doesnt move with it and stays on the same place. Any Ideas? Tnx.

You need to translate the canvas with the movement before doing the fill. Also remember to beginPath before making your shape.
var pattern = document.getElementById('pattern');
var can = document.getElementById('can');
var ctx = can.getContext('2d');
var w = can.width = 300;
var h = can.height = 200;
pattern.width = pattern.height = 20;
var pctx = pattern.getContext('2d');
pctx.fillStyle = 'white';
pctx.fillRect(0, 0, 20, 20);
pctx.fillStyle = 'red';
pctx.fillRect(0, 0, 10, 10);
pctx.fillRect(10, 10, 10, 10);
pctx.fillRect(2, 12, 6, 6);
pctx.fillRect(12, 2, 6, 6);
var p = ctx.createPattern(pattern, 'repeat');
var x = 50;
var y = 50;
var radius = 50;
var xStep = 1;
var yStep = 2;
var trans = "on";
function ani() {
ctx.fillStyle = "black";
ctx.fillRect(0, 0, w, h);
ctx.moveTo(x, y);
// beginPath clears any existing path
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 20);
ctx.fillStyle = p;
if (trans == "on") {
ctx.save();
// translate will offset the fill pattern
ctx.translate(x, y);
ctx.fill();
ctx.restore();
} else {
ctx.fill();
}
x += xStep;
y += yStep;
if (x > (w - radius) || x < radius) xStep *= -1;
if (y > (h - radius) || y < radius) yStep *= -1;
requestAnimationFrame(ani);
}
ani();
var btnOff = document.getElementById('trans_off');
var btnOn = document.getElementById('trans_on');
btnOff.addEventListener('click',function(){
btnOff.className = "selected";
btnOn.className = "";
trans = "off";
});
btnOn.addEventListener('click',function(){
btnOff.className = "";
btnOn.className = "selected";
trans = "on";
});
body {
background-color: #555555;
color: #F0F0F0;
font-family: sans-serif;
}
button {
color: #cccccc;
background-color: #333333;
border: 1px solid #cccccc;
}
button.selected {
color: white;
font-weight: bold;
}
Translate
<button id="trans_off">off</button>
<button id="trans_on" class="selected">on</button>
<hr/>
<canvas id="pattern"></canvas>
<canvas id="can"></canvas>

Related

How to use: globalCompositeOperation on multiple objects in JavaScript Canvas

I'm attempting to create a circle menu in JavaScript canvas, something that would look similar to this:
Here is the code I'm using:
let canvas = document.querySelector("#canvas");
canvas.width = 500;
canvas.height = 500;
let ctx = canvas.getContext("2d");
ctx.fillStyle = "rgba(0,0,0,.45)"; // color
let circlePath = [];
let centerCircle = new Path2D();
for (let t = 0; t < 8; t++) {
circlePath[t] = new Path2D();
circlePath[t].moveTo(250, 250);
circlePath[t].arc(
250,
250,
190,
Math.PI * 2 * 0.125 * t,
Math.PI * 2 * 0.125 * t + Math.PI * 2 * 0.1175
);
circlePath[t].closePath();
ctx.fill(circlePath[t]);
}
ctx.fillStyle = "#fff";
centerCircle.moveTo(250, 250);
centerCircle.arc(250,250,100,0,2*Math.PI);
ctx.fill(centerCircle);
canvas.addEventListener("mousemove", function (event) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let t = 0; t < 8; t++) {
if (ctx.isPointInPath(circlePath[t], event.offsetX, event.offsetY)) {
ctx.fillStyle = "blue";
} else {
ctx.fillStyle = "rgba(0,0,0,.45)";
}
ctx.fill(circlePath[t]);
}
ctx.fillStyle = "#fff";
centerCircle.moveTo(250, 250);
centerCircle.arc(250,250,100,0,2*Math.PI);
//ctx.globalCompositeOperation = "destination-out";
ctx.fill(centerCircle);
});
#canvas {
border: 1px solid #000;
background: green;
};
<canvas id="canvas"></canvas>
The problem I am having is that when I try to use ctx.globalCompositeOperation = "destination-out"; to "punch out" a hole in the midle of the arcs using the white circle, it makes all of the objects disappear.
Thank you in advance for any input provided.
Figured it out! Had to place ctx.globalCompositeOperation = "destination-out"; in the right places, followed by: ctx.globalCompositeOperation = "source-over";
Here is the updated code:
let canvas = document.querySelector("#canvas");
canvas.width = 500;
canvas.height = 500;
let ctx = canvas.getContext("2d");
ctx.fillStyle = "rgba(0,0,0,.45)"; // color
let circlePath = [];
let centerCircle = new Path2D();
for (let t = 0; t < 8; t++) {
circlePath[t] = new Path2D();
circlePath[t].moveTo(250, 250);
circlePath[t].arc(
250,
250,
190,
Math.PI * 2 * 0.125 * t,
Math.PI * 2 * 0.125 * t + Math.PI * 2 * 0.1175
);
circlePath[t].closePath();
ctx.fill(circlePath[t]);
}
ctx.fillStyle = "#fff";
centerCircle.moveTo(250, 250);
centerCircle.arc(250,250,100,0,2*Math.PI);
ctx.globalCompositeOperation = "destination-out";
ctx.fill(centerCircle);
ctx.globalCompositeOperation = "source-over";
canvas.addEventListener("mousemove", function (event) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let t = 0; t < 8; t++) {
if (ctx.isPointInPath(circlePath[t], event.offsetX, event.offsetY)) {
ctx.fillStyle = "blue";
} else {
ctx.fillStyle = "rgba(0,0,0,.45)";
}
ctx.fill(circlePath[t]);
}
ctx.fillStyle = "#fff";
centerCircle.moveTo(250, 250);
centerCircle.arc(250,250,100,0,2*Math.PI);
ctx.globalCompositeOperation = "destination-out";
ctx.fill(centerCircle);
ctx.globalCompositeOperation = "source-over";
});
#canvas {
border: 1px solid #000;
background: green;
};
<canvas id="canvas"></canvas>

Aligning text inside rectangle of html5 canvas

I have resizable rectangle, and I wish to have right-aligned text (day numbers) next to it.
what I have now:
(also when resizing the text does not really align vertically)
what I wish to have:
Is there a way to fill the text and align it inside a drawn rectangle? Other suggestions are welcome too.
js.do code
function dayRect(day) {
const days = ["I","II","III","IV","V","VI","VII"];
context.beginPath();
//maybe align the text inside this rect somehow
context.rect(0, day*h/7, 3*w/27, h/7);
context.stroke();
context.font = "0.5rem Arial";
context.fillStyle = "#fff";
context.fillText(days[day], 0, (day+1)*h/7);
}
I've changed a few things in your code since I wasn't able to see anything. You need to use context.textAlign="right" for your text and move it to a different position. I hope it helps.
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
var canvas = document.getElementById("posHourCanvas");
var context = canvas.getContext('2d');
canvas.width=600,canvas.height=300;
var boxes = [];
function init() {
context.clearRect(0, 0, canvas.width, canvas.height);
boxes.length = 0;
const strokeWidth = 0.6;
//canvas.width = $('#two')[0].clientWidth;
var cellSize = canvas.width/27;
canvas.height = 7/27 * canvas.width;
var x = y = 0;
draw(x,y,canvas.width,canvas.height,cellSize,strokeWidth);
}
function Box(x, y, day, hour) {
this.x = x;
this.y = y;
this.day = day;
this.hour = hour;
}
function draw(x, y, w, h, cellSize, strokeWidth) {
let onePixel = cellSize * strokeWidth;
cellSize = cellSize * (1 - strokeWidth);
context.beginPath();
context.lineWidth = 1;
context.strokeStyle = 'rgba(0, 0, 0, 1)';
const rectCoordinates = {
x: x+3*w/27,
y: y,
w: w-3*w/27,
h: h
}
context.rect(rectCoordinates.x, y, rectCoordinates.w, h);
context.fillStyle = 'white';
context.fill();
context.stroke();
let offX = rectCoordinates.w/24 + rectCoordinates.x;
let offY = h/7;
for (let i = 0; i < 7; i++) {
dayRect(i);
context.beginPath();
context.moveTo(0, offY);
context.lineTo(w, offY);
context.strokeStyle = "black";
context.stroke();
offY+=h/7;
}
for (let i = 0; i < 24; i++) {
context.beginPath();
context.moveTo(offX, 0);
context.lineTo(offX, h);
context.stroke();
offX+=rectCoordinates.w/24;
}
function dayRect(day) {
const days = ["I","II","III","IV","V","VI","VII"];
context.beginPath();
context.rect(0, day*h/7, 3*w/27, h/7);
context.stroke();
context.font = "0.5rem Arial";
context.fillStyle = "#fff";
context.textAlign="right";
context.fillText(days[day], 60, (day+1)*h/7);
}
}
init();
body {
margin: auto;
color: white;
background-color: black;
min-height: 100vh;
}
<div id="parent">
<div>text above</div>
<div id="two">
<canvas id="posHourCanvas" width="600" height="300"></canvas>
</div>
<div>text under</div>
</div>

How to change the color of the circle on canvas every n seconds?

How could the size of the shadow change, every n seconds? I guess you have to constantly create a new circle and eliminate the previous one? How would this be done? And also, is not there a more optimal way?
function main() {
var canvas = document.getElementsByTagName("CANVAS")[0],
ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = document.documentElement.scrollHeight;
var cW = canvas.width,
cH = canvas.height;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, cW, cH);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "#FFF";
ctx.shadowBlur = 5;
ctx.shadowColor = "#FFF";
ctx.arc(cW/2, cH/2, 50, 0, 2 * Math.PI, false);
ctx.fill();
ctx.closePath();
}
window.addEventListener("load", main);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<canvas></canvas>
</body>
</html>
Create a setInterval & an array of colors. Use Math.random to randomly select any color.
Modify the main function to accept colors as two parameters.
function main(bckColor, circleColor) {
var canvas = document.getElementsByTagName("CANVAS")[0],
ctx = canvas.getContext("2d");
if (canvas.height) {
canvas.height = 0;
}
canvas.width = window.innerWidth;
canvas.height = document.documentElement.scrollHeight;
var cW = canvas.width,
cH = canvas.height;
ctx.fillStyle = bckColor || "#000";
//ctx.fillStyle = "red" ;
ctx.fillRect(0, 0, cW, cH);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = circleColor || "#FFF";
ctx.shadowBlur = 5;
ctx.shadowColor = "#FFF";
ctx.arc(cW / 2, cH / 2, 50, 0, 2 * Math.PI, false);
ctx.fill();
ctx.closePath();
}
var colorArray = ['red', 'green', 'yellow', 'blue', 'pink', 'brown', 'orange']
var changeColor = setInterval(function() {
let bckColor = colorArray[Math.floor(Math.random() * 7 + 1)];
let circleColor = colorArray[Math.floor(Math.random() * 7 + 1)];
main(bckColor, circleColor)
}, 2000)
window.addEventListener("load", main);
<canvas></canvas>
instead of animating the canvas itself with a redraw every x seconds, i would suggest using an overlay , create a circle div, position it over the canvas' circle and animate its shadow using css, you'll have all the controls you want like the shadow's color and distance, animation speed ..etc.
here's a fiddle ( the overlay is better positionned )
function main() {
var canvas = document.getElementsByTagName("CANVAS")[0],
ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = document.documentElement.scrollHeight;
var cW = canvas.width,
cH = canvas.height;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, cW, cH);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "#FFF";
ctx.shadowBlur = 5;
ctx.shadowColor = "#FFF";
ctx.arc(cW / 2, cH / 2, 50, 0, 2 * Math.PI, false);
ctx.fill();
ctx.closePath();
// position the overlay over the circle
overlay.style.top = (cH / 2 - 99) + 'px'
overlay.style.left = (cW / 2 - 50) + 'px'
}
window.addEventListener("load", main);
main()
const animationDuration = 2;
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
overlay.style.animationDuration = animationDuration + 's';
setInterval(function() {
overlay.style.color = getRandomColor()
}, animationDuration * 1000)
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
canvas {
width: 100vw;
height: 100vh;
display: block;
}
#overlay {
border-radius: 50%;
background: none;
animation: shadow linear infinite;
margin: auto;
transform: translate(0, 50%);
color: green;
position: absolute;
z-index: 99;
width: 100px;
height: 93px;
}
#keyframes shadow {
0% 100% {
box-shadow: 0 0 0
}
50% {
box-shadow: 0 0 50px 20px
}
}
<canvas></canvas>
<div id="overlay">
</div>

Add ID to each rendered element inside canvas

I need little help.
How can I add a text inside each rendered element inside canvas ?
here is a fiddle representing my idea:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x_width = canvas.width;
var y_height = canvas.height;
var dx = 2;
var dy = -2;
var ballRadius = 10;
var data = [
[1,0.506,0.648],
[2,0.253,0.433],
[5,0.339,0.445],
[7,0.396,0.569],
[8,0.271,0.583],
[9,0.307,0.187],
[10,0.431,0.213],
[12,0.71,1.045],
[13,0.2,0.259],
[14,0.272,0.259],
[15,0.477,0.379]
];
for (var i = 0; i<=data.length-1; i++) {
var x = x_width*data[i][1];
var y = y_height*data[i][2];
var id = data[i][0];
drawPlayer (id, x,y);
}
function drawPlayer(id, x, y) {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.fillText(id, 0, 0);
ctx.closePath();
}
drawPlayer();
//setInterval(draw , 100);
#myCanvas {
border: 1px solid red;
}
<canvas id="myCanvas" width="480" height="320"></canvas>
<div class="play-btn-hld">
<button class="play">Graj</button>
</div>
Can I somehow add a text inside each element ? Idealy the text should be the data[i][0] number. Is it possible ? I can not wrap my head around it.
Or Should I use classic html and css to create similar effect ?
Cheers
you need to set the x and y position of the text to be the same as the circle's position.
plus measuring the text in order to have it aligned nicely.
here you go:
function drawPlayer(id, x, y) {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
const textWidth = ctx.measureText(id);
const textHeight = 12 * 0.5;
ctx.font = "12px Arial"
ctx.fillStyle = "#fff";
ctx.fillText(id, x-textWidth.width/2, y+textHeight/2);
}

how to add label to the chart created using canvas

hello all i am able to display the chart but i need to add labels to the chart the labels are given below but i am not able to display it in the chart any help pls thanks in advance
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var lastend = 0;
var data = [20,40]; // If you add more data values make sure you add more colors
var labels = ["leavebalance", "leaveavailability"];
var myTotal = 0; // Automatically calculated so don't touch
var myColor = ['red','green']; // Colors of each slice
for (var e = 0; e < data.length; e++) {
myTotal += data[e];
}
//alert(myTotal);
for (var i = 0; i < data.length; i++) {
ctx.fillStyle = myColor[i];
//ctx.fillText(labels[i]);
//ctx.fillText = labels[i];
ctx.beginPath();
ctx.moveTo(canvas.width / 2, canvas.height / 2);
// Arc Parameters: x, y, radius, startingAngle (radians), endingAngle (radians), antiClockwise (boolean)
ctx.arc(canvas.width / 2, canvas.height / 2, canvas.height / 2, lastend, lastend + (Math.PI * 2 * (data[i] / myTotal)), false);
ctx.lineTo(canvas.width / 2, canvas.height / 2);
ctx.fill();
lastend += Math.PI * 2 * (data[i] / myTotal);
}
<canvas id="canvas" width="200" height="150" >
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
Here's one way to apply labels to each wedge in a pie chart:
Calculate the middle angle between the starting & ending angles for each wedge in the pie.
Calculate the [x,y] that is on the middle angle and near the circumference.
Set textAlign & textBaseline so drawn text is centered on the calculated [x,y].
Draw the label at the calculated [x,y] fillText('20',x,y)
Here's annotated code and a Demo:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
ctx.lineWidth = 2;
ctx.font = '12px verdana';
ctx.textAlign='center';
ctx.textBaseline='middle';
var PI2 = Math.PI * 2;
var myColor = ['red','green','blue'];
var myData = [25,35,40];
var cx = 150;
var cy = 150;
var radius = 100;
pieChart(myData, myColor);
function pieChart(data, colors) {
var total = 0;
for (var i = 0; i < data.length; i++) {
total += data[i];
}
var sweeps = []
for (var i = 0; i < data.length; i++) {
sweeps.push(data[i] / total * PI2);
}
var accumAngle = 0;
for (var i = 0; i < sweeps.length; i++) {
drawWedge(accumAngle, accumAngle + sweeps[i], colors[i], data[i]);
accumAngle += sweeps[i];
}
}
function drawWedge(startAngle, endAngle, fill, label) {
// draw the wedge
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.arc(cx, cy, radius, startAngle, endAngle, false);
ctx.closePath();
ctx.fillStyle = fill;
ctx.strokeStyle = 'black';
ctx.fill();
ctx.stroke();
// draw the label
var midAngle = startAngle + (endAngle - startAngle) / 2;
var labelRadius = radius * .75;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
ctx.fillStyle = 'white';
ctx.fillText(label, x, y);
}
body {
background-color: ivory;
padding: 10px;
}
#canvas {
border: 1px solid red;
}
<canvas id="canvas" width=300 height=300></canvas>

Categories

Resources