I'm trying to just make a rectangle but nothing will appear, just the background. I've tried ctx.fill, ctx.fillStyle etc. nothing works:
I'm refering to this part
fill(77, 66, 66);
rect(10,200,100,100);
Here is the whole code for the page
var ctx, W, H;
window.onload = function() {
var canvas = document.getElementById("canvas");
W = window.innerWidth;
H = window.innerHeight;
canvas.width = W;
canvas.height = H;
ctx = canvas.getContext("2d");
setInterval(draw, 1);
function draw() {
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "#E6E6FF"; // this part does appear
ctx.fillRect(0, 0, W, H);
fill(77, 66, 66); // this doesn't appear
rect(10,200,100,100);
}
}
Thanks
You need to call fill and rect on the canvas context.
Also you need to change the fillStyle otherwise you're drawing a rectangle with the same color as the background and it won't show.
var ctx, W, H;
window.onload = function() {
var canvas = document.getElementById("canvas");
W = window.innerWidth;
H = window.innerHeight;
canvas.width = W;
canvas.height = H;
ctx = canvas.getContext("2d");
setTimeout(draw, 1);
function draw() {
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "#E6E6FF";
ctx.fillRect(0, 0, W, H);
ctx.fillStyle = "red"; // need this otherwise the rect will be the same color as the background
ctx.rect(10, 200, 100, 100); // needs to be called on the canvas context
ctx.fill(); // needs to be called on the canvas context, it will fill any path not already filled in.
}
}
You are filling both areas with the same color, and you have to use the context to perform fill functions. you also need to create the rect BEFORE you fill it.
Try this on for size: https://jsfiddle.net/szbk6f67/3/
var ctx, W, H;
window.onload = function () {
var canvas = document.getElementById("canvas");
W = 400;
H = 400;
canvas.width = W;
canvas.height = H;
ctx = canvas.getContext("2d");
setInterval(draw, 1);
function draw() {
ctx.globalCompositeOperation = 'source-over';
ctx.fillStyle = 'gray';
ctx.fillRect(0, 0, W, H);
ctx.fillStyle = 'black';
ctx.rect(10, 200, 100, 100);
ctx.fill();
}
}
Related
So the objective is to place a circle randomly on the screen, and if the circle was clicked, remove this old circle and make a new circle.
I'm having a problem with removing the old point and making a new one. Instead of removing the old one, it keeps it, makes a new circle and eventually does whatever this is after a bit of clicking:
This is how my code looks like:
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.cursor = "crosshair";
function randSpot() {
var X = Math.floor(Math.random() * canvas.width) + 10;
var Y = Math.floor(Math.random() * canvas.height) + 10;
ctx.arc(X, Y, 5.5, 0, 2 * Math.PI);
ctx.fillStyle = 'red';
ctx.fill();
document.body.addEventListener('click', function(e) {
if (ctx.isPointInPath(e.clientX, e.clientY)) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
randSpot()
}
});
}
randSpot()
What am I doing wrong and how can I fix it?
You forgot to begin a new path
ctx.beginPath();
I had to modify the code to make it run in the snippet
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.cursor = "crosshair";
function randSpot() {
var X = Math.floor(Math.random() * canvas.width) + 10;
var Y = Math.floor(Math.random() * canvas.height) + 10;
ctx.beginPath();
ctx.arc(X, Y, 5.5, 0, 2 * Math.PI);
ctx.fillStyle = 'red';
ctx.fill();
}
randSpot()
document.body.addEventListener('click', function(e) {
// I had to remove the following condition
// ctx.isPointInPath(e.clientX, e.clientY)
// because the code didn't wanted to work with the snippet
// but it's unrelated to the problem
ctx.clearRect(0, 0, canvas.width, canvas.height);
randSpot()
});
I'm adding multiple rectangles in canvas which could collide with each other. The outer stroke should be displayed on the outer part of both rectangles or the rectangle shapes should be merged in to one producing the expected result.
See picture bellow
It has to be cut because it will display the content under the canvas. See live example with background image: https://jsfiddle.net/0qpgf5un/
In the code example bellow rectangles are being added on top of each other as you can see in the first example of the picture.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var offsetX = 150;
var offsetY = 150;
var w = 200;
var h = 100;
ctx.fillStyle = "red";
ctx.rect(0, 0, 600, 600);
ctx.fill();
ctx.clearRect(offsetX,offsetY, w, h);
ctx.strokeRect(offsetX, offsetY, w, h);
ctx.clearRect(offsetX-50,offsetY+50, w, h);
ctx.strokeRect(offsetX-50, offsetY+50, w, h);
Is there ways to achieve it without writing complex calculations of each path, since the collision of rectangles can be unintentional and diverse ?
Edit:
What I am trying to achieve is a similar functionality like in youtube's feedback form where when editing screenshot you can highlight items and the border then is merged.
Just add one more clearRect() (the first one)
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var offsetX = 150;
var offsetY = 150;
var w = 200;
var h = 100;
ctx.fillStyle = "red";
ctx.rect(0, 0, 600, 600);
ctx.fill();
ctx.clearRect(offsetX,offsetY, w, h);
ctx.strokeRect(offsetX, offsetY, w, h);
ctx.clearRect(offsetX-50,offsetY+50, w, h);
ctx.strokeRect(offsetX-50, offsetY+50, w, h);
ctx.clearRect(offsetX,offsetY, w, h);
https://jsfiddle.net/kt3yjhpc/
You can skip clearing the first rectangle and then clear it after you stroke the second one.
The clearPrev function will clear the area inside the strokes of the initial rectangle.
let canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
offsetX = 70,
offsetY = 20,
w = 200,
h = 100,
strokeWidth = 5;
ctx.fillStyle = '#F00'
ctx.rect(0, 0, 600, 600);
ctx.fill();
ctx.strokeStyle = '#0FF';
ctx.lineWidth = strokeWidth;
//ctx.clearRect(offsetX, offsetY, w, h); <-- Do not need to do this, if we clear below...
ctx.strokeRect(offsetX, offsetY, w, h);
ctx.clearRect(offsetX - 50, offsetY + 50, w, h);
ctx.strokeRect(offsetX - 50, offsetY + 50, w, h);
clearPrev(ctx, offsetX, offsetY, w, h); // Clear previous
function clearPrev(ctx, x, y, w, h) {
let startOffset = Math.round(ctx.lineWidth / 2) - 1,
endOffset = strokeWidth - 1;
ctx.clearRect(x + startOffset, y + startOffset, w - endOffset, h - endOffset);
}
<canvas id="canvas" width="290" height="190"></canvas>
When you want to clear the canvas with complex shapes, forget about clearRect, it's not the only one able to produce transparent pixels.
Instead, have a look at compositing.
So your shape is really border-line, but I think you'll benefit from using this already:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var offsetX = 150;
var offsetY = 150;
var w = 200;
var h = 100;
ctx.lineWidth = 2;
ctx.fillStyle = "red";
ctx.fillRect(0, 0, 600, 600);
// declare our complex shape as a single sub-path
ctx.beginPath()
ctx.rect(offsetX,offsetY, w, h);
ctx.rect(offsetX-50, offsetY+50, w, h);
// now we can paint it
// first the stroke, because we want to erase what's inside the fill-area
ctx.stroke();
// now to erase, we switch to destination-out compositing mode
ctx.globalCompositeOperation = 'destination-out';
// fill the inner path
ctx.fill();
// we're done
// If you wish to go back to normal mode later
ctx.globalCompositeOperation = 'source-over';
body { background: linear-gradient(blue,yellow); }
<canvas id="canvas" width="600" height="600"></canvas>
I'm using the multiply value for the globalCompositeOperation property to apply a tint to a clipped region of an image. It works, but the bottom edge of the image sometimes gets a white border.
// Code goes here
document.addEventListener("DOMContentLoaded", function() {
var canvas = document.getElementById('myCanvas');
var img = new Image();
img.onload = function() {
render();
}
img.src = 'http://i.imgur.com/qiJkgK9.jpg';
function render() {
canvas.width = img.width * 2;
canvas.height = img.height * 2;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
ctx.save();
ctx.beginPath();
ctx.rect(200, 200, 200, 200);
ctx.clip();
ctx.globalCompositeOperation = 'multiply';
ctx.fillStyle = 'red';
ctx.fill();
ctx.restore();
ctx.save();
ctx.beginPath();
ctx.rect(300, 100, 200, 200);
ctx.clip();
ctx.globalCompositeOperation = 'multiply';
ctx.fillStyle = 'red';
ctx.fill();
ctx.restore();
}
});
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<canvas id="myCanvas"></canvas>
</body>
</html>
How to prevent the border from appearing OR is there a better way to apply multiply tint to an image?
You can just use fillRect to the exact rectangle you're looking for instead of clip and fill, which is causing your clipping issue.
var canvas = document.getElementById('myCanvas');
function render() {
canvas.width = img.width * 2;
canvas.height = img.height * 2;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'multiply';
ctx.fillStyle = 'red';
ctx.fillRect(200, 200, 200, 200);
ctx.fillRect(300, 100, 200, 200);
}
var img = new Image();
img.onload = render;
img.src = 'http://i.imgur.com/qiJkgK9.jpg';
<canvas id="myCanvas"></canvas>
The Menu
I want to make it so when the user clicks play it takes you to another HTML page. I have placed a rect over the play area and want to make it so the rect is what the user is clicking as the play text is part of a single image.
This is the JS for my rect:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// Red rectangle
ctx.beginPath();
ctx.lineWidth = "6";
ctx.strokeStyle = "red";
ctx.rect(125, 140, 230, 90);
ctx.stroke();
You can achieve it like this
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = draw;
function draw() {
canvas.width = this.width;
canvas.height = this.height;
ctx.drawImage(this, 0, 0);
ctx.beginPath();
ctx.lineWidth = "6";
ctx.strokeStyle = "red";
ctx.rect(101, 114, 184, 71);
ctx.stroke();
}
img.src = 'https://i.stack.imgur.com/M3x29.jpg';
canvas.onclick = function(e) {
if (e.offsetX > 102 && e.offsetX < 286 && e.offsetY > 110 && e.offsetY < 182) {
window.location = 'http://stackoverflow.com'; // another html page location
}
};
<canvas id="canvas"></canvas>
I have a canvas element:
<canvas id="canvas" width="100" height="100"></canvas>
And some JavaScript to make canvas full screen:
var canvas, ctx, w, h;
function start() {
canvas = $("#canvas")[0];
ctx = canvas.getContext("2d");
w = $('body').innerWidth();
$("#canvas").width(w);
$("#canvas").height(w);
w = $("#canvas").width();
h = $("#canvas").height();
if(typeof game_loop != "undefined") clearInterval(game_loop);
game_loop = setInterval(paint, 60);
}
function paint() {
ctx.fillStyle = "white";
ctx.fillRect(0, 0, w, h);
ctx.strokeStyle = "blue";
ctx.strokeRect(0, 0, 50, 50);
}
I don't know why I get one big square not 50x50. Can you help?
To actually resize the canvas (as in have more pixles) you'll need to set the width/height attributes. jQuerys width()/height() sets the css values. Resulting in a stretched canvas element consisting of the same number of pixels as before. Instead use:
$('#canvas').prop({
width: 400, // the 400 is just arbitrary
height: 400
});
Or, as per Alnitaks comment, you could of course just as well assign the values directly:
canvas.width = 400;
canvas.height = 400;
Here is a simple example of drawing a square on resize using width/height.
Example: http://jsfiddle.net/Ubv7X/
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var paint = function() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Draw background
ctx.fillStyle = 'rgb(255, 255, 255)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw rect
var rect_size=50;
ctx.fillStyle = 'rgb(0, 0, 255)';
ctx.fillRect(canvas.width/2-(rect_size/2), canvas.height/2-(rect_size/2),
rect_size, rect_size);
}
setInterval(paint, 60);