Can't change color from javascript - javascript

I can't get to change the color of the stroke when mouseovering the button. I've tried solving it by myself bu i can't.
var canvas = document.getElementById("canvas1");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(17, 7);
ctx.bezierCurveTo(13, -8, 26, 21, 12, 26);
ctx.bezierCurveTo(-2, 31, 59, 64, 33, 18);
ctx.lineWidth = 8;
ctx.strokeStyle = "#3d7eb8";
if (document.getElementById("one").style.backgroundColor == "#3d7eb8"){
ctx.strokeStyle = "#fffced";
}
ctx.stroke();
function button1hover (){
document.getElementById("one").style = "background-color: #3d7eb8";
}
function button1unhover (){
document.getElementById("one").style = "background-color: #fffced";
}
<button onmouseout="button1unhover()" onmouseover="button1hover()" id="one" class="button column center">
<canvas height="50px" width="50px" id="canvas1"></canvas>
<p>Inici</p>
</button>

This really is no job vor JS, this can all be accomplished with CSS and a tiny inline SVG for the curve.
#one {
background-color: #fffced;
}
#one svg {
width: 50px;
height: 50px;
}
#one:hover {
background-color: #3d7eb8;
}
#one path {
fill: none;
stroke-width: 8px;
stroke: #3d7eb8;
}
#one:hover path {
stroke: #fffced;
}
<button id="one" class="button column center">
<svg><path d="M 17 7 C 13 -8 26 21 12 26 -2 31 59 64 33 18" /></svg>
<p>Inici</p>
</button>
and even the CSS can be nicer if you use less or sass/scss
#one {
background-color: #fffced;
svg {
width: 50px;
height: 50px;
}
path {
fill: none;
stroke-width: 8px;
stroke: #3d7eb8;
}
&:hover {
background-color: #3d7eb8;
path {
stroke: #fffced;
}
}
}
To answer the question why your code does not work: You render the canvas exactly once, at the beginning. To change it, you'd have to re-render it inside of button1hover() and button1unhover() with the resperctive color.
And even then, document.getElementById("one").style.backgroundColor == "#3d7eb8" ain't guaranteed to work. Because, depending on the Browser, .style.backgroundColor may return the color as rgb(...) value.
So better define a variable that stores the state and toggle/check that.

As said before, this is better done in css.
However, if you wish to do it in JS, you could try something like that :
var canvas = document.getElementById("canvas1");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(17, 7);
ctx.bezierCurveTo(13, -8, 26, 21, 12, 26);
ctx.bezierCurveTo(-2, 31, 59, 64, 33, 18);
ctx.lineWidth = 8;
ctx.strokeStyle = "#3d7eb8";
ctx.stroke();
function button1hover() {
this.style.background = "#3d7eb8";
ctx.strokeStyle = "#fffced";
ctx.stroke();
}
function button1unhover() {
this.style.background = "#fffced";
ctx.strokeStyle = "#3d7eb8";
ctx.stroke();
}
document.getElementById('one').addEventListener("mouseover",button1hover);
document.getElementById('one').addEventListener("mouseout",button1unhover);
<button id="one" class="button column center">
<canvas height="50px" width="50px" id="canvas1"></canvas>
<p>Inici</p>
</button>
eventListeners are your friends for this kind of things, as for the canvas, I'm not sure there is a better option than redrawing it every time.

Related

Replicate Canvas resize in a Div

There's any way to replicate this scale behavior in a div ?
Here's an example of the behavior I wanted to reproduce within the div. I already have the movement part, and I just wanted to know about the resizing.
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script>
<style>
body {
margin: 0px;
padding: 0px;
}
#wrapper {
position: relative;
border: 1px solid #9C9898;
width: 578px;
height: 200px;
}
#buttonWrapper {
position: absolute;
width: 30px;
top: 2px;
right: 2px;
}
input[type="button"] {
padding: 5px;
width: 30px;
margin: 0px 0px 2px 0px;
}
</style>
<script>
function draw(scale, translatePos) {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
// clear canvas
context.clearRect(0, 0, canvas.width, canvas.height);
context.save();
context.translate(translatePos.x, translatePos.y);
context.scale(scale, scale);
context.beginPath(); // begin custom shape
context.moveTo(-119, -20);
context.bezierCurveTo(-159, 0, -159, 50, -59, 50);
context.bezierCurveTo(-39, 80, 31, 80, 51, 50);
context.bezierCurveTo(131, 50, 131, 20, 101, 0);
context.bezierCurveTo(141, -60, 81, -70, 51, -50);
context.bezierCurveTo(31, -95, -39, -80, -39, -50);
context.bezierCurveTo(-89, -95, -139, -80, -119, -20);
context.closePath(); // complete custom shape
var grd = context.createLinearGradient(-59, -100, 81, 100);
grd.addColorStop(0, "#8ED6FF"); // light blue
grd.addColorStop(1, "#004CB3"); // dark blue
context.fillStyle = grd;
context.fill();
context.lineWidth = 5;
context.strokeStyle = "#0000ff";
context.stroke();
context.restore();
}
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var translatePos = {
x: canvas.width / 2,
y: canvas.height / 2
};
var scale = 1.0;
var scaleMultiplier = 0.8;
var startDragOffset = {};
var mouseDown = false;
// add button event listeners
document.getElementById("plus").addEventListener("click", function() {
scale /= scaleMultiplier;
draw(scale, translatePos);
}, false);
document.getElementById("minus").addEventListener("click", function() {
scale *= scaleMultiplier;
draw(scale, translatePos);
}, false);
// add event listeners to handle screen drag
canvas.addEventListener("mousedown", function(evt) {
mouseDown = true;
startDragOffset.x = evt.clientX - translatePos.x;
startDragOffset.y = evt.clientY - translatePos.y;
});
canvas.addEventListener("mouseup", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mouseover", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mouseout", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mousemove", function(evt) {
if (mouseDown) {
translatePos.x = evt.clientX - startDragOffset.x;
translatePos.y = evt.clientY - startDragOffset.y;
draw(scale, translatePos);
}
});
draw(scale, translatePos);
};
jQuery(document).ready(function() {
$("#wrapper").mouseover(function(e) {
$('#status').html(e.pageX + ', ' + e.pageY);
});
})
</script>
</head>
<body onmousedown="return false;">
<div id="wrapper">
<canvas id="myCanvas" width="578" height="200">
</canvas>
<div id="buttonWrapper">
<input type="button" id="plus" value="+"><input type="button" id="minus" value="-">
</div>
</div>
<h2 id="status">
0, 0
</h2>
</body>
</html>
I tried to use css scale, but it resizes the div too, I want to modify only the space and the elements inside it.

Is there something I am doing wrong by trying to make a rectangle?

I am trying to make a rectangle by filling it with html/javascript, but for some reason, even though it's only a few lines of code, I can't figure out what I'm doing wrong here
I've already tried in the code using strokeStyle and not using the viewport , I also tried using var canvas = document.getElementById("myCanvas"); like this, with double quotes
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgb(255, 255, 255)";
ctx.fillRect(0, 0, 40, 40);
<canvas id="myCanvas" style="border: 1px solid black; height: 50px; width: 100vw; max-width: 100%;"></canvas>
I truly don't know anymore what I'm doing wrong and I just want to make a rectangle
You're drawing a white rectangle on a white canvas.
Change ctx.fillStyle = "rgb(255, 255, 255)"; to be a color that shows up on a white background:
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgb(255, 0, 0)";
ctx.fillRect(0, 0, 40, 40);
<canvas id="myCanvas" style="border: 1px solid black; height: 50px; width: 100vw; max-width: 100%;"></canvas>

How to animate properly in a <canvas>?

So I want to recreate this simple animation effect, which uses a <canavs> :
https://codepen.io/w3devcampus/pen/PpLLKY
HTML:
<html lang="en">
<head>
<meta charset="utf-8">
<title>Draw a monster in a canvas</title>
</head>
<body>
<canvas id="myCanvas" width="200" height="200"></canvas>
</body>
</html>
JavaScript:
function mainLoop() {
ctx.clearRect(0, 0, w, h);
drawMyMonster(xMonster, yMonster);
xMonster += monsterSpeed;
if (((xMonster + 100)> w) || (xMonster < 0)) {
monsterSpeed = -monsterSpeed;
}
}
function drawMyMonster(x, y) {
ctx.save();
ctx.translate(x, y);
ctx.strokeRect(0, 0, 100, 100);
ctx.fillRect(20, 20, 10, 10);
ctx.fillRect(65, 20, 10, 10);
ctx.strokeRect(45, 40, 10, 40);
ctx.strokeRect(35, 84, 30, 10);
ctx.fillRect(38, 84, 10, 10);
ctx.fillRect(52, 84, 10, 10);
ctx.restore();
}
So, I did recreate it, but it wouldn't behave normally. Instead of displaying one frame at a time, it stacks all the frames up each other in the canvas. Here's my version:
https://codepen.io/Undefined_Variable/pen/LraLJQ
HTML:
<html>
<head>
<title>CanvasThingy</title>
</head>
<body>
<canvas id="CanvasForMonster">
No support for you scrub!
</canvas>
</body>
</html>
JavaScript:
var myCanvas, context, w, h;
var xMonster = 60;
var yMonster = 30;
var monsterSpeed = 1;
window.onload = function initial(){
myCanvas = document.body.querySelector('#CanvasForMonster');
w = myCanvas.style.width;
h = myCanvas.style.height;
context = myCanvas.getContext('2d');
ClearCanvas();
}
function ClearCanvas(){
context.clearRect(0, 0, w, h);
DrawFMLface(xMonster, yMonster);
xMonster += monsterSpeed;
if(((xMonster + 175) > 299) || (xMonster < 0) ){
monsterSpeed = -monsterSpeed;
}
requestAnimationFrame(ClearCanvas);
}
function DrawFMLface(x, y){
context.save();
context.translate(x, y);
context.strokeRect(0, 4, 175, 80);
context.strokeStyle = 'black';
context.fillRect(40, 10, 20, 20);
context.strokeStyle = 'black';
context.fillRect(110, 10, 20, 20);
context.strokeStyle = 'black';
context.strokeRect(85, 40, 1, 15);
context.strokeStyle = 'black';
context.strokeRect(42, 70, 90, 0);
context.strokeStyle = 'black';
context.restore();
}
Please tell me how to do this properly without jQuery AT ALL, please. I'm still learning and I don't want any jQuery/Angular/React etc. in my code, please!
Your problem is that the previous faces are not being cleared. The clearing is supposed to be done with this line:
ctx.clearRect(0, 0, w, h);
The problem is that w and h are not set correctly when this is run, so not enough of the canvas is cleared.
This is where you set w and h:
w = myCanvas.style.width;
h = myCanvas.style.height;
This will only work if the width and height were set with CSS, e.g. with an HTML attribute style="width: 200px; height: 200px;", and if you called parseInt to convert the CSS style strings into numbers. But in fact the canvas element’s width and height were set with width and height HTML attributes directly. So you should set w and h with HTMLCanvasElement’s width and height properties:
w = canvas.width;
h = canvas.height;
The original Codepen sets them this way.
Just in case you were looking for a possibly easier way to do this, you can actually avoid JavaScript entirely when creating a simple animation like this by using CSS animations:
#CanvasForMonster {
position: relative;
width: 200px;
height: 200px;
border: 1px solid #000;
}
#Monster {
position: absolute;
top: 25%;
width: 50%;
height: 50%;
animation: bounce 2s alternate linear infinite;
}
#keyframes bounce {
from { left: 0; }
to { left: 50%; }
}
#Monster div {
position: absolute;
}
#Monster .stroke {
border: 1px solid #000;
}
#Monster .fill {
background-color: #000;
}
#Monster .head {
left: 0;
top: 0;
width: 100%;
height: 100%;
}
#Monster .eye {
width: 10%;
height: 10%;
}
#Monster .eye-left {
left: 25%;
top: 25%;
}
#Monster .eye-right {
left: 65%;
top: 25%;
}
#Monster .nose {
left: 50%;
top: 50%;
width: 1px;
height: 10%;
}
#Monster .mouth {
left: 25%;
top: 75%;
width: 50%;
height: 0;
}
<div id="CanvasForMonster">
<div id="Monster">
<div class="stroke head"></div>
<div class="fill eye eye-left"></div>
<div class="fill eye eye-right"></div>
<div class="stroke nose"></div>
<div class="stroke mouth"></div>
</div>
</div>
Everything you have is alright.
The problem is your Globals.
The width of the canvas should be set to:
w = myCanvas.width;
Height set to:
h = myCanvas.height;
You have both set as:
w = myCanvas.style.width;
h = myCanvas.style.height;
Which will not work.
Here is the fork (Demo).
I would highly recommend using JQuery when working with canvas.
When using canvas it should be noted that you want too reference canvas.height, and canvas.width as much as possible rather then using a global that points at the height, and width of the css style.

How do I change X-Y positions of an circle on a canvas

I'm trying out canvas for the first time. After creating a circle I want to be able to change the position of the center of this circle at the click of a button. But I am unable to figure how to do so. Can someone suggest a method for it?
#button{
height: 25px;
width:125px;
border: 1px solid black;
text-align: center;
cursor: pointer;
}
<html>
<head></head>
<body>
<div id="button" onclick="changePosition()">Click here</div>
<canvas id="testCanvas" width="500px" height="500px"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("testCanvas");
var a = canvas.getContext("2d");
a.fillStyle = "#b22222";
a.beginPath();
a.arc(100,100,25,0,2*Math.PI);
a.fill();
function changePosition(){
//what do I put here??
}
</script>
</body>
</html>
You need to redraw the scene. Create a function that resets the canvas and then draws the circle
var canvas = document.getElementById("testCanvas");
var ctx = canvas.getContext("2d");
var circlePos = {
left: 100,
top: 100,
}
function renderCircle( circlePos ) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#b22222";
ctx.beginPath();
ctx.arc(circlePos.left, circlePos.top, 25, 0, 2 * Math.PI);
ctx.fill();
}
function changePosition() {
circlePos.left += 10;
if ( circlePos.left > canvas.width ) {
circlePos.left = 0;
}
renderCircle( circlePos );
}
changePosition();
#button {
height: 25px;
width: 125px;
border: 1px solid black;
text-align: center;
cursor: pointer;
}
<button onclick="changePosition()">Click here</button>
<canvas id="testCanvas" width="500" height="200"></canvas>

how to make a shadow in HTML canvas

I need to draw a canvas rect with shadow which has shadows on four sides of the rect, similar to a div has style as "box-shadow":"0px 0px 5px 5px"
You can use context.shadowColor plus context.shadowBlur to create the box-shadow effect.
Canvas's blur is very light so you must often overdraw the blurs to make them prominent.
Here's my version of your box-shadow: 0 0 5px 5px:
Example annotated code:
shadowRect(10,10,105,45,5,'red');
function shadowRect(x,y,w,h,repeats,color){
// set stroke & shadow to the same color
ctx.strokeStyle=color;
ctx.shadowColor=color;
// set initial blur of 3px
ctx.shadowBlur=3;
// repeatedly overdraw the blur to make it prominent
for(var i=0;i<repeats;i++){
// increase the size of blur
ctx.shadowBlur+=0.25;
// stroke the rect (which also draws its shadow)
ctx.strokeRect(x,y,w,h);
}
// cancel shadowing by making the shadowColor transparent
ctx.shadowColor='rgba(0,0,0,0)';
// restroke the interior of the rect for a more solid colored center
ctx.lineWidth=2;
ctx.strokeRect(x+2,y+2,w-4,h-4);
}
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
shadowRect(10,10,105,45,5,'red');
function shadowRect(x,y,w,h,repeats,color){
// set stroke & shadow to the same color
ctx.strokeStyle=color;
ctx.shadowColor=color;
// set initial blur of 3px
ctx.shadowBlur=3;
// repeatedly overdraw the blur to make it prominent
for(var i=0;i<repeats;i++){
// increase the size of blur
ctx.shadowBlur+=0.25;
// stroke the rect (which also draws its shadow)
ctx.strokeRect(x,y,w,h);
}
// cancel shadowing by making the shadowColor transparent
ctx.shadowColor='rgba(0,0,0,0)';
// restroke the interior of the rect for a more solid colored center
ctx.lineWidth=2;
ctx.strokeRect(x+2,y+2,w-4,h-4);
}
body{ background-color: ivory; padding:10px;}
<h4>box-shadow: 0 0 5px 5px red</h4>
<div style="box-shadow: 0 0 5px 5px red; height: 40px; width:100px;"></div>
<br>
<h4>Canvas "box-shadow" using context shadowing</h4>
<canvas id="canvas" width=200 height=100></canvas>
CanvasRenderingContext2D.shadowColor property in combination with shadowBlur, shadowOffsetX, or shadowOffsetY does just that.
Example:
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const shadowRect = ({
x = 15,
y = 15,
w = 100,
h = 40,
fillStyle = 'tomato',
shadowOffsetX = 0,
shadowOffsetY = 3,
shadowBlur = 15,
shadowColor = "rgba(21, 24, 50, 0.3)"
} = {}) => {
ctx.shadowOffsetX = shadowOffsetX;
ctx.shadowOffsetY = shadowOffsetY;
ctx.shadowBlur = shadowBlur;
ctx.shadowColor = shadowColor;
ctx.fillStyle = fillStyle;
ctx.fillRect(x, y, w, h);
}
shadowRect({ fillStyle: '#C99DFE' });
body {
background-color: #E5E5E5;
padding: 10px;
font-family: sans-serif;
font-size: 16px;
}
.shadowRect {
margin: 15px 0 0 15px;
background-color: #C99DFE;
box-shadow: 0px 3px 15px rgba(21, 24, 50, 0.3);
border-radius: 2px;
width:100px;
height: 40px;
}
<h4>CSS</h4>
<pre>
width: 100px;
height: 40px;
margin: 15px 0 0 15px;
background-color: #C99DFE;
box-shadow: 0px 3px 15px rgba(21, 24, 50, 0.3);
</pre>
<div class="shadowRect"></div>
<br>
<h4>Canvas</h4>
<pre>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
ctx.shadowOffsetX = 15;
ctx.shadowOffsetY = 15;
ctx.shadowBlur = 15;
ctx.shadowColor = 'rgba(21, 24, 50, 0.3)';
ctx.fillStyle = '#C99DFE';
ctx.fillRect(15, 15, 100, 40);
</pre>
<canvas id="canvas" width=200 height=100></canvas>

Categories