In my HTML canvas, I'm trying to apply the style shadowBlur, ONLY to the text element that says 'Artwork 1'.
But current if you see by running the code snippet, the shadowBlur gets applied to every other element too.
I also tried using ctx.save() and ctx.restore() too but it doesnt seem to work.
Any help is appreciated
var container = 'body';
var size = {
x: $(container).width(),
y: $(container).height()
};
var canvas = $('<canvas/>').attr({width: size.x, height: size.y}).appendTo(container),
ctx = canvas.get(0).getContext("2d");
ctx.globalCompositeOperation = 'xor';
window.requestFrame = (function(){
return window.requestAnimationFrame
})();
function render(){
ctx.clearRect(0,0,size.x,size.y);
ctx.lineWidth = 10;
ctx.strokeStyle = '#fff';
ctx.shadowColor = '#fff';
ctx.beginPath();
ctx.moveTo(-20,size.y/2);
for(var x = 0; x < size.x; x++){
ctx.lineTo(x,size.y/2+0.6*(20),1,1);
if (x == 100.00) {
ctx.font = "20px Arial";
ctx.fillStyle = "red";
ctx.fillText("Artwork 1 ",x,(size.y/2+0.6*(20)- 25 ));
ctx.shadowBlur = 50; /* this is applied to all elements instead of just the text*/
ctx.save();
ctx.fillStyle = "red";
ctx.fillRect(x, (size.y/2+0.6*(20)- 10 ), 20, 20);
}
if (x == 300.00) {
ctx.font = "20px Arial";
ctx.fillStyle = "red";
ctx.fillText("Artwork 2 ",x,(size.y/2+0.6*(20)- 25 ));
ctx.fillStyle = "red";
ctx.fillRect(x, (size.y/2+0.6*(20)- 10 ), 20, 20);
}
}
ctx.stroke();
requestFrame(render);
} /* END fn render */
render();
html, body {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
overflow: hidden;
background-color: #000;
}
html canvas, body canvas {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
}
<div>test</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Set the shadow before rendering the text, then turn it off afterward:
ctx.shadowBlur = 20; // call before draw operation require shadow
ctx.fillText("Artwork 1 ",x,(size.y/2+0.6*(20)- 25 ));
ctx.shadowBlur = 0; // remove shadow
Notice since the shadow in the previous code is overdrawn several times the result of new code will make it appear "weaker" which either force you to use a smaller blur radius (as shown) or to overdraw the text a couple of times (will require a different composition mode than xor).
The save() call can be removed.
var container = 'body';
var size = {
x: $(container).width(),
y: $(container).height()
};
var canvas = $('<canvas/>').attr({width: size.x, height: size.y}).appendTo(container),
ctx = canvas.get(0).getContext("2d");
ctx.globalCompositeOperation = 'xor';
window.requestFrame = (function(){
return window.requestAnimationFrame
})();
function render(){
ctx.clearRect(0,0,size.x,size.y);
ctx.lineWidth = 10;
ctx.strokeStyle = '#fff';
ctx.shadowColor = '#fff';
ctx.beginPath();
ctx.moveTo(-20,size.y/2);
for(var x = 0; x < size.x; x++){
ctx.lineTo(x,size.y/2+0.6*(20),1,1);
if (x == 100.00) {
ctx.font = "20px Arial";
ctx.fillStyle = "red";
ctx.shadowBlur = 20; /* this is applied to all elements instead of just the text*/
ctx.fillText("Artwork 1 ",x,(size.y/2+0.6*(20)- 25 ));
ctx.shadowBlur = 0;
ctx.fillStyle = "red";
ctx.fillRect(x, (size.y/2+0.6*(20)- 10 ), 20, 20);
}
if (x == 300.00) {
ctx.font = "20px Arial";
ctx.fillStyle = "red";
ctx.fillText("Artwork 2 ",x,(size.y/2+0.6*(20)- 25 ));
ctx.fillStyle = "red";
ctx.fillRect(x, (size.y/2+0.6*(20)- 10 ), 20, 20);
}
}
ctx.stroke();
requestFrame(render);
} /* END fn render */
render();
html, body {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
overflow: hidden;
background-color: #000;
}
html canvas, body canvas {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
}
<div>test</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Related
I am doing a project where the user selects what programming language they enjoy out of a radio box. It sets an object to the Local Storage and creates a bar graph and the bars go up depending on what choice the select. I'm having trouble though where if the user selects the language for the third time, it turns out what is in the image. I change the height each time and for some reason it also goes over the axis. I just want the height to change. I'm not super familiar with the canvas. Is there a way I could go about doing this? I just simply want the bar to start at the origin and go up, but not down.
Code below:
<!--
Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
Click nbfs://nbhost/SystemFileSystem/Templates/Other/html.html to edit this template
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Extra Credit Challenge</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
#entryArea{
border: 1px solid black;
width: 30%;
border-radius: 100px;
text-align: center;
margin: auto;
}
#myCanvas{
border-radius: 25px;
border: 1px;
}
#submitButton{
border-radius: 15px;
background-color:lightblue;
font-size: 25px;
width: 30%;
}
input{
font-size: 25px;
}
#resetButton{
border-radius: 15px;
background-color:lightblue;
font-size: 25px;
width: 30%;
}
</style>
</head>
<body onload="init()">
<canvas id="myCanvas" width="500" height="450" style="border:1px solid #000000;"></canvas>
<div id="entryArea">
<p style="font-size: 20px">What is your favorite programming language?</p>
<p><input name="language" type="radio" value="Web Design">Web Design</p>
<p><input name="language" type="radio" value="Java">Java</p>
<p><input name="language" type="radio" value="Python">Python</p>
<p><input name="language" type="radio" value="Other">Other</p>
<button id="submitButton">Submit</button><br><br>
<button id="resetButton">Reset</button>
</div>
<script>
function init(){
unCheckItems();
drawAxes();
walkThroughStorage();
document.getElementById("submitButton").addEventListener("click", setItemToStorage);
document.getElementById("resetButton").addEventListener("click", clearCanvas);
}
function walkThroughStorage(){
var ele = document.getElementById("entryArea").querySelectorAll("input");
var curTextStorage = localStorage.getItem("ClickedBoxes");
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
curTextStorage = JSON.parse(curTextStorage);
if(curTextStorage !== null){
for(let i = 0; i<ele.length; i++){
let height = (curTextStorage[ele[i].value] || 0) * 40;
if(ele[i].value === "Web Design"){
if(curTextStorage[ele[i].value] > 1){
ctx.rect(80, 310-(height/2), 30, height);
ctx.lineWidth = 1;
ctx.stroke();
}
if(curTextStorage[ele[i].value] === 1){
ctx.rect(80, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
else if(ele[i].value === "Java"){
if(curTextStorage[ele[i].value] > 1){
ctx.rect(180, 310-(height/2), 30, height);
ctx.lineWidth = 1;
ctx.stroke();
}
if(curTextStorage[ele[i].value] === 1){
ctx.rect(180, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
else if(ele[i].value === "Python"){
if(curTextStorage[ele[i].value] > 1){
ctx.rect(255, 310-(height/2), 30, height);
ctx.lineWidth = 1;
ctx.stroke();
}
if(curTextStorage[ele[i].value] === 1){
ctx.rect(255, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
else{
if(curTextStorage[ele[i].value] > 1){
ctx.rect(335, 310-(height/2), 30, height);
ctx.lineWidth = 1;
ctx.stroke();
}
if(curTextStorage[ele[i].value] === 1){
ctx.rect(335, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
}
}
ctx.closePath();
}
function drawAxes(){
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
//draw x axis
ctx.moveTo(20,350);
ctx.lineTo(500,350);
ctx.lineWidth = 4;
ctx.stroke();
ctx.closePath();
//draw y axis
ctx.beginPath();
ctx.moveTo(40,400);
ctx.lineTo(40,0);
ctx.stroke();
ctx.closePath();
//draw names at the bottom
ctx.font = "15px Arial";
ctx.fillText("Web Design", 60,370);
ctx.fillText("Java", 180,370);
ctx.fillText("Python", 250,370);
ctx.fillText("Other", 330,370);
}
function unCheckItems(){
var ele = document.getElementById("entryArea").querySelectorAll("input");
for(let i = 0; i < ele.length; i++) {
if(ele[i].checked){
ele[i].checked = false;
}
}
}
function setItemToStorage(){
var savedClicks = localStorage.getItem("ClickedBoxes");
let clickDict = JSON.parse(savedClicks) || {};
var ele = document.getElementById("entryArea").querySelectorAll("input");
for(let i = 0; i < ele.length; i++){
if(ele[i].checked){
if(!clickDict[ele[i].value]){
clickDict[ele[i].value]=1;
}
else//the key of 1,2,3,4 or 5 (contents of curRandNum) exist in theDict so add one to its value
{
clickDict[ele[i].value] += 1;
}
}
localStorage.setItem("ClickedBoxes",JSON.stringify(clickDict));
}
drawBars();
}
function drawBars(){
var savedClicks = localStorage.getItem("ClickedBoxes");
savedClicks = JSON.parse(savedClicks);
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
var ele = document.getElementById("entryArea").querySelectorAll("input");
for(let i = 0; i < ele.length; i++) {
let height = (savedClicks[ele[i].value] || 0) * 40;
if(ele[i].checked){
if(ele[i].value === "Web Design"){
if(savedClicks[ele[i].value] > 1){
clearBar();
//ctx.clearRect(80, 300, 30, 40);
ctx.rect(80, 310-(height/2), 30, height);
ctx.lineWidth = 0;
ctx.stroke();
}
if(savedClicks[ele[i].value] === 1){
ctx.rect(80, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
else if(ele[i].value === "Java"){
if(savedClicks[ele[i].value] > 1){
clearBar();
ctx.rect(180, 310-(height/2), 30, height);
ctx.lineWidth = 0;
ctx.stroke();
}
if(savedClicks[ele[i].value] === 1){
ctx.rect(180, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
else if(ele[i].value === "Python"){
if(savedClicks[ele[i].value] > 1){
clearBar();
ctx.rect(255, 310-(height/2), 30, height);
ctx.lineWidth = 0;
ctx.stroke();
}
if(savedClicks[ele[i].value] === 1){
ctx.rect(255, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
else{
if(savedClicks[ele[i].value] > 1){
clearBar();
ctx.rect(335, 310-(height/2), 30, height);
ctx.lineWidth = 0;
ctx.stroke();
}
if(savedClicks[ele[i].value] === 1){
ctx.rect(335, 310, 30, 40);
ctx.lineWidth = 1;
ctx.stroke();
}
}
}
}
ctx.closePath();
}
function clearBar(){
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, c.width, c.height);
init();
}
function clearCanvas(){
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, c.width, c.height);
localStorage.clear();
init();
}
</script>
</body>
</html>
Here is the image photo
Thanks in advance!
You have a miscalculation when drawing your rectanlges.
The lines
ctx.rect(255, 310-(height/2), 30, height);
should be changed to
ctx.rect(255, 350 - height, 30, height);
That's a bit too much copy-paste. The basic issue is what #Ruan shows: if you want to draw a rectangle which ends at y=350, you just subtract its height from 350, without any division.
Other things added/removed here are:
0-1-many are not handled separately any more, a zero-sized rectangle conveniently stays inside the horizontal axis, so you can draw it, and 40 doesn't differ from 1*40, so there is no need to draw it separately
the code parts for drawing the 4 bars differred in their x coordinates only, even if their spacing is irregular, they can be picked from an array, see the [80, 180, 255, 335][i] part - bit nasty, but does the job
walkwhatever was removed, it was doing the same as drawBars()
a single reDraw() method was added for handling redraw of everything
duplicated canvas clearing removed
instead a clear() method was added for clearing existing data and calling reDraw()
init() is not reused anymore, as that would add click handlers again, which usually leads to interesting behaviour.
(And a fake localStorage has been added, simply because it's disabled for snippets hosted here on StackOverflow)
// this is just for simulating localStorage here on StackOverflow
const localStorage = {m: new Map(),
getItem: function(k) {return this.m.has(k) ? this.m.get(k) : null;},
setItem: function(k, v) {this.m.set(k, v);},
clear: function() {this.m.clear();}};
function init() {
unCheckItems();
drawAxes();
drawBars();
document.getElementById("submitButton").addEventListener("click", setItemToStorage);
document.getElementById("resetButton").addEventListener("click", clear);
}
function drawAxes() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
//draw x axis
ctx.moveTo(20, 350);
ctx.lineTo(500, 350);
ctx.lineWidth = 4;
ctx.stroke();
ctx.closePath();
//draw y axis
ctx.beginPath();
ctx.moveTo(40, 400);
ctx.lineTo(40, 0);
ctx.stroke();
ctx.closePath();
//draw names at the bottom
ctx.font = "15px Arial";
ctx.fillText("Web Design", 60, 370);
ctx.fillText("Java", 180, 370);
ctx.fillText("Python", 250, 370);
ctx.fillText("Other", 330, 370);
}
function unCheckItems() {
var ele = document.getElementById("entryArea").querySelectorAll("input");
for (let i = 0; i < ele.length; i++) {
if (ele[i].checked) {
ele[i].checked = false;
}
}
}
function setItemToStorage() {
var savedClicks = localStorage.getItem("ClickedBoxes");
let clickDict = JSON.parse(savedClicks) || {};
var ele = document.getElementById("entryArea").querySelectorAll("input");
for (let i = 0; i < ele.length; i++) {
if (ele[i].checked) {
if (!clickDict[ele[i].value]) {
clickDict[ele[i].value] = 1;
} else //the key of 1,2,3,4 or 5 (contents of curRandNum) exist in theDict so add one to its value
{
clickDict[ele[i].value] += 1;
}
}
localStorage.setItem("ClickedBoxes", JSON.stringify(clickDict));
}
reDraw();
}
function drawBars() {
var savedClicks = localStorage.getItem("ClickedBoxes");
savedClicks = JSON.parse(savedClicks) || {};
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.lineWidth = 1;
var ele = document.getElementById("entryArea").querySelectorAll("input");
for (let i = 0; i < ele.length; i++) {
let height = (savedClicks[ele[i].value] || 0) * 40;
ctx.strokeRect([80, 180, 255, 335][i], 350 - height, 30, height);
}
}
function clearCanvas() {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, c.width, c.height);
}
function reDraw() {
unCheckItems();
clearCanvas();
drawAxes();
drawBars();
}
function clear() {
localStorage.clear();
reDraw();
}
init(); // "onload"
#entryArea {
border: 1px solid black;
width: 30%;
border-radius: 100px;
text-align: center;
margin: auto;
}
#myCanvas {
border-radius: 25px;
border: 1px;
}
#submitButton {
border-radius: 15px;
background-color: lightblue;
font-size: 25px;
width: 30%;
}
input {
font-size: 25px;
}
#resetButton {
border-radius: 15px;
background-color: lightblue;
font-size: 25px;
width: 30%;
}
<canvas id="myCanvas" width="500" height="450" style="border:1px solid #000000;"></canvas>
<div id="entryArea">
<p style="font-size: 20px">What is your favorite programming language?</p>
<p><input name="language" type="radio" value="Web Design">Web Design</p>
<p><input name="language" type="radio" value="Java">Java</p>
<p><input name="language" type="radio" value="Python">Python</p>
<p><input name="language" type="radio" value="Other">Other</p>
<button id="submitButton">Submit</button><br><br>
<button id="resetButton">Reset</button>
</div>
I'm writing a drawing app in HTML5 Canvas, which includes a freehand draw with the mouse.
I have a problem whereby the mouse move to draw the stroke is not under the crosshair cursor. The X co-ordinate is fine, but the Y coordinate is offset by a varying amount as the mouse pointer is moved (closer at the top of the page, drifts further away as we closer to the bottom).
It has something to do with the 'header bar' div at the top.
Here is the code.
<style>
#divContainer {
width: 100%;
height: 100%;
}
#divHeader {
position: absolute;
left: 0px;
top: 0px;
right: 0px;
height: 28px;
background-color: #333;
}
#divContentArea {
position: absolute;
left: 0px;
top: 29px;
right: 0px;
bottom: 5px;
}
#divContentCenter {
position: absolute;
top: 0px;
left: 0px;
bottom: 0px;
right:0px;
}
.canvascontainer {
position: relative;
overflow: auto;
width:100%;
height:100%;
}
.canvas {
cursor: crosshair;
width: 100%;
height: 100%;
position:absolute;
left:0px;
top:0px;
z-index: 2;
}
.maincanvas {
cursor: crosshair;
width: 100%;
height: 100%;
position:absolute;
left:0px;
top:0px;
z-index: 1;
}
</style>
<div id="divContainer">
<div id="divHeader">
The Header
</div>
<div id="divContentArea">
<div id="divContentCenter">
<div id='canvascontainer' class='canvascontainer' >
<canvas id="canvas" class='canvas'>
Sorry, your browser does not support a canvas object.
</canvas>
<canvas id="maincanvas" class='maincanvas'>
Sorry, your browser does not support a canvas object.
</canvas>
</div>
</div>
</div>
</div>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
const canrect = canvas.getBoundingClientRect();
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var maincanvas = document.getElementById('maincanvas');
var maincontext = maincanvas.getContext('2d');
maincanvas.width = window.innerWidth;
maincanvas.height = window.innerHeight;
var lastPoint;
var startPoint;
var isDrawing = false;
context.lineWidth = 3;
context.lineJoin = context.lineCap = 'round';
context.setLineDash([0, 0]);
context.globalAlpha = 1.0;
function drawGuideLines() {
for ( i = 0; i < canvas.height; i += 20 ) {
context.beginPath();
context.setLineDash([2, 2]);
context.lineWidth = 1;
if ( i % 60 == 0 ) {
context.lineWidth = 2;
}
context.strokeStyle = '#ccc';
context.moveTo(0,i);
context.lineTo(canvas.width,i);
context.stroke();
}
for ( i = 0; i < canvas.width; i += 20 ) {
context.beginPath();
context.setLineDash([2, 2]);
context.lineWidth = 1;
if ( i % 60 == 0 ) {
context.lineWidth = 2;
}
context.strokeStyle = '#ccc';
context.moveTo(i,0);
context.lineTo(i, canvas.height);
context.stroke();
}
}
function getMousePos(e) {
return {
x: e.offsetX - canrect.left,
y: e.offsetY + canrect.top
};
}
function clearPage() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
function copyToMain () {
maincontext.drawImage(canvas, 0, 0);
clearPage();
}
canvas.onmousedown = function(e) {
isDrawing = true;
canvas.addEventListener("mousemove", drawDirectPath, false);
lastPoint = { x: e.clientX, y: e.clientY };
lastPoint = { x: e.offsetX, y: e.offsetY };
// lastPoint = { x: e.offsetX, y: e.PageY };
lastPoint = getMousePos(e);
};
function drawDirectPath(e) {
if (!isDrawing) return;
context.beginPath();
context.setLineDash([0, 0]);
context.lineWidth = 3;
context.strokeStyle = 'red';
context.fillStyle = 'red';
//show_mouse_info(e, 'GetMousePos:' + getMousePos(e).x + ', ' + getMousePos(e).y);
//show_mouse_info(e, 'boundrect:' + canrect.x + ', ' + canrect.y);
//mx = e.clientX;
//my = e.clientY;
mx = e.offsetX;
my = e.offsetY;
context.moveTo(lastPoint.x, lastPoint.y);
context.lineTo(mx, my);
context.stroke();
lastPoint = { x: mx, y: my };
}
canvas.onmouseup = function() {
isDrawing = false;
copyToMain ();
};
canvas.onmouseleave = function() {
isDrawing = false;
copyToMain ();
};
drawGuideLines();
</script>
I have tried using OffsetX/Y, PageX/Y, clinetX/Y to see if these make a difference but I cannot solve the problem.
The test, click the mouse in the top right or top left and drag/draw down diagonally to the opposite bottom corner to see the effect.
Don't give the canvas a width and height of 100% using CSS.
.canvas {
cursor: crosshair;
position:absolute;
left:0px;
top:0px;
z-index: 2;
}
Couple other things you may want to consider
Always declare variables for (let i =...
Don't make getBoundingClientRect() a const. The reason for this is if you needed to add a resize function you wouldn't be able to change the bounds because the variable holds the original bounds.
You are assigning lastPoint over and over. Not really sure what this is about.
lastPoint = { x: e.clientX, y: e.clientY };
lastPoint = { x: e.offsetX, y: e.offsetY };
// lastPoint = { x: e.offsetX, y: e.PageY };
lastPoint = getMousePos(e);
I wanted to use this cool matrix background for my web application but it covers all of my elements(div's, headers, paragraphs etc.).
I've tried to fix this with css but it doesn't work.
So now I'm stuck and asking you for help.
Here is my code from CodePen:
const canvas = document.getElementById('canv');
const ctx = canvas.getContext('2d');
const w = canvas.width = document.body.offsetWidth;
const h = canvas.height = document.body.offsetHeight;
const cols = Math.floor(w / 20) + 1;
const ypos = Array(cols).fill(0);
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, w, h);
function matrix () {
ctx.fillStyle = '#0001';
ctx.fillRect(0, 0, w, h);
ctx.fillStyle = '#0f0';
ctx.font = '15pt monospace';
ypos.forEach((y, ind) => {
const text = String.fromCharCode(Math.random() * 128);
const x = ind * 20;
ctx.fillText(text, x, y);
if (y > 100 + Math.random() * 10000) ypos[ind] = 0;
else ypos[ind] = y + 20;
});
}
setInterval(matrix, 50);
body {
margin: 0;
height: 100vh;
width: 100vw;
}
.container{
background-color: white;
}
<canvas id='canv'>
<div class='container'>
<p>Some div with login in</p>
</div>
</canvas>
Is there someway to fix it?
Thanks for your attention and help.
Here's a possible solution:
const canvas = document.getElementById('canv');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');
let cols = Math.floor(window.innerWidth / 20) + 1;
let ypos = Array(cols).fill(0);
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
function matrix () {
const w = window.innerWidth;
const h = window.innerHeight;
if (canvas.width !== w) {
canvas.width = w;
cols = Math.floor(window.innerWidth / 20) + 1;
ypos = Array(cols).fill(0);
}
if (canvas.height !== h) {
canvas.height = h;
}
ctx.fillStyle = '#0001';
ctx.fillRect(0, 0, w, h);
ctx.fillStyle = '#0f0';
ctx.font = '15pt monospace';
ypos.forEach((y, ind) => {
const text = String.fromCharCode(Math.random() * 128);
const x = ind * 20;
ctx.fillText(text, x, y);
if (y > 100 + Math.random() * 10000) ypos[ind] = 0;
else ypos[ind] = y + 20;
});
}
setInterval(matrix, 50);
body {
margin: 0;
background-color: #000;
}
.container {
background-color: rgba(255, 255, 255, 0.85);
margin: 50px 10%;
padding: 3rem;
position: relative;
z-index: 1;
}
#canv {
position: fixed;
top: 0;
left: 0;
}
<canvas id='canv'></canvas>
<div class='container'>
<p>Some div with login in</p>
</div>
Play around with the CSS of .container to make it look like you want. Don't remove the position and z-index (they are needed to keep it on top of the <canvas>).
Note: The CSS required to place .container on top is rather simple and it's not the reason I added the answer for.
The reason is because your matrix script was not responsive. I made minor mods to it and it now resizes when viewport size changes.
Welcome to SO.
I'm working on a pixel art project. What I was expecting to do here is be able to click any box inside the grid and render it with the the color from a color input.
I managed to understand how the loop works to create a grid using canvas and javascript. Next, I created a function called colorPicker() which allows me to click on any of the grid cells and take the value from the color input and render it that color. I used canvas.addEventListener("click", function(event) { ... })
and passed variables xCoord and yCoord with the value of event.x and event.y. This allows me to return the position of the mouse on click inside the grid.
The problem I'm running into right now is that it is only rendering 1 square out of all 400 I have drawn on the grid. The rendering works, it's just I can only click one box and render its color from the input.
Can anyone provide me with some help to solve this function just using the javascript logic I currently have right now?
var title = document.getElementById("title");
var canvas = document.getElementById("canvas");
var color = document.getElementById("color");
var btn = document.getElementById("btn");
var ctx = canvas.getContext("2d");
// The function that draws the grid
function drawGrid() {
ctx.fillStyle = "#009EFF";
ctx.fillRect(0, 0, 400, 400);
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
// The for loop that draws the x-axis
for (x = 0; x <= 400; x += 20) {
ctx.moveTo(x, 0);
ctx.lineTo(x, 400);
ctx.stroke();
}
// The for loop that draws the y-axis
for (y = 0; y <= 400; y += 20) {
ctx.moveTo(0, y);
ctx.lineTo(400, y);
ctx.stroke();
}
}
drawGrid();
// Function that clicks and fill grid boxes w / color
function colorPicker() {
canvas.addEventListener("click", function(event) {
var newColor = color.value;
ctx.fillStyle = newColor;
xCoord = event.x;
yCoord = event.y;
ctx.fillRect(0, 0, 20, 20);
console.log(xCoord, yCoord);
console.log(newColor);
});
}
colorPicker();
#canvas {
border: 1px solid black;
background-size: 100%;
display: block;
margin-top: 50px;
margin-left: auto;
margin-right: auto;
padding-left: 0;
padding-right: 0;
}
<div class="color-wheel">
Color: <input type="color" id="color" />
</div>
<canvas id="canvas" width="400" height="400"></canvas>
Your problem is this line:
ctx.fillRect(0, 0, 20, 20);
Instead of filling the clicked cell, you’re filling only the upper left cell on every click.
Currently you’re just using (0, 0) here, when you should be calculating this position from the cursor. The coordinates used by the canvas and the cursor are different though, so you’ll need to write a conversion function:
function mousePosToCanvasPos(mouseX, mouseY) {
var canvasPos = canvas.getBoundingClientRect();
return {
x: Math.floor((mouseX - canvasPos.x) / 20) * 20,
y: Math.floor((mouseY - canvasPos.y) / 20) * 20,
};
}
The mousePosToCanvasPos() function gets the current rendered position of the canvas (canvasPos), and calculates the offset of the cursor from the upper left corner of the canvas (mouse_ - canvasPos._). It then rounds this value down to the nearest multiple of 20 to return the upper left corner of the clicked cell (Math.floor((mouse_ - canvasPos._) / 20) * 20). If you change your cell size to something other than 20, be sure to change it in this function too. Or better yet, extract the constant (var cellSize = 20).
Adding this function to your code gives us:
var title = document.getElementById("title");
var canvas = document.getElementById("canvas");
var color = document.getElementById("color");
var btn = document.getElementById("btn");
var ctx = canvas.getContext("2d");
// The function that draws the grid
function drawGrid() {
ctx.fillStyle = "#009EFF";
ctx.fillRect(0, 0, 400, 400);
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
// The for loop that draws the x-axis
for (x = 0; x <= 400; x += 20) {
ctx.moveTo(x, 0);
ctx.lineTo(x, 400);
ctx.stroke();
}
// The for loop that draws the y-axis
for (y = 0; y <= 400; y += 20) {
ctx.moveTo(0, y);
ctx.lineTo(400, y);
ctx.stroke();
}
}
drawGrid();
function mousePosToCanvasPos(mouseX, mouseY) {
var canvasPos = canvas.getBoundingClientRect();
return {
x: Math.floor((mouseX - canvasPos.x) / 20) * 20,
y: Math.floor((mouseY - canvasPos.y) / 20) * 20,
};
}
// Function that clicks and fill grid boxes w / color
function colorPicker() {
canvas.addEventListener("click", function(event) {
var newColor = color.value;
ctx.fillStyle = newColor;
var canvasCellPos = mousePosToCanvasPos(event.x, event.y);
ctx.fillRect(canvasCellPos.x, canvasCellPos.y, 20, 20);
console.log(event.x, event.y);
console.log(newColor);
});
}
colorPicker();
#canvas {
border: 1px solid black;
background-size: 100%;
display: block;
margin-top: 50px;
margin-left: auto;
margin-right: auto;
padding-left: 0;
padding-right: 0;
}
<div class="color-wheel">
Color: <input type="color" id="color" />
</div>
<canvas id="canvas" width="400" height="400"></canvas>
You’ll notice that something’s still not quite right here: every time you fill a cell, it makes its border thinner. To solve this, you need to remove one pixel from each side of your fillRect:
ctx.fillRect(canvasCellPos.x + 1, canvasCellPos.y + 1, 18, 18);
var title = document.getElementById("title");
var canvas = document.getElementById("canvas");
var color = document.getElementById("color");
var btn = document.getElementById("btn");
var ctx = canvas.getContext("2d");
// The function that draws the grid
function drawGrid() {
ctx.fillStyle = "#009EFF";
ctx.fillRect(0, 0, 400, 400);
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
// The for loop that draws the x-axis
for (x = 0; x <= 400; x += 20) {
ctx.moveTo(x, 0);
ctx.lineTo(x, 400);
ctx.stroke();
}
// The for loop that draws the y-axis
for (y = 0; y <= 400; y += 20) {
ctx.moveTo(0, y);
ctx.lineTo(400, y);
ctx.stroke();
}
}
drawGrid();
function mousePosToCanvasPos(mouseX, mouseY) {
var canvasPos = canvas.getBoundingClientRect();
return {
x: Math.floor((mouseX - canvasPos.x) / 20) * 20,
y: Math.floor((mouseY - canvasPos.y) / 20) * 20,
};
}
// Function that clicks and fill grid boxes w / color
function colorPicker() {
canvas.addEventListener("click", function(event) {
var newColor = color.value;
ctx.fillStyle = newColor;
var canvasCellPos = mousePosToCanvasPos(event.x, event.y);
ctx.fillRect(canvasCellPos.x + 1, canvasCellPos.y + 1, 18, 18);
console.log(event.x, event.y);
console.log(newColor);
});
}
colorPicker();
#canvas {
border: 1px solid black;
background-size: 100%;
display: block;
margin-top: 50px;
margin-left: auto;
margin-right: auto;
padding-left: 0;
padding-right: 0;
}
<div class="color-wheel">
Color: <input type="color" id="color" />
</div>
<canvas id="canvas" width="400" height="400"></canvas>
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>