how to make a shadow in HTML canvas - javascript

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>

Related

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 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>

getting canvas pixel data is wrong after setting it with css

i am trying to get the rgb color data from a painted canvas.
with this function:
function pick(event) {
var x = event.layerX;
var y = event.layerY;
var pixel = ctx.getImageData(x, y, 1, 1);
var data = pixel.data;
$("#color").val(pixel.data.toString());
console.log(pixel.data.toString());
}
however, when i am setting the canvas element to any relative width (80%/100%), like this:
canvas {
/*width: 100%;*/ /*when i set the width, the rgb values are incorrect .... */
/*margin-left: auto;
margin-right: auto;
display: block;*/
}
i am no longer getting correct values from this function.
attaching my JS Fiddle:
https://jsfiddle.net/iliran11/ay9nf1p9/
You need to find the difference in width when you stretch and multiply that to the coordinates.
//color names
var basecolors = ["(255,0,0)",
"(255,128,0)",
"(255,255,0)",
"(128,255,0)",
"(0,255,0)",
"(0,255,128)",
"(0,255,255)",
"(0,128,255)",
"(0,0,255)",
"(128,0,255)",
"(255,0,255)",
"(255,0,128)",
"(128,128,128)"
];
//init
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
var heightPerColor = height / basecolors.length;
//init cursor
var xCursor = 0;
var yCursor = 0;
drawPallete(width, height, "s");
function drawPallete(width, height, type) {
canvas.width = width;
canvas.height = height;
ctx.clearRect(0, 0, canvas.width, canvas.height);
var Grad = ctx.createLinearGradient(0, 0, canvas.width, 0);
Grad.addColorStop(0 / 6, '#F00');
Grad.addColorStop(1 / 6, '#FF0');
Grad.addColorStop(2 / 6, '#0F0');
Grad.addColorStop(3 / 6, '#0FF');
Grad.addColorStop(4 / 6, '#00F');
Grad.addColorStop(5 / 6, '#F0F');
Grad.addColorStop(6 / 6, '#F00');
ctx.fillStyle = Grad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
;
function pick(event) {
var canvas = document.getElementById("canvas");
//Here comes the stretch offset
//var off = (1 / canvas.width) * canvas.offsetWidth;
var off = (1 / canvas.offsetWidth) * canvas.width;
//Applying offset
var x = Math.floor(event.layerX * off) - Math.floor(canvas.offsetLeft * off);
var y = Math.floor(event.layerY * off) - Math.floor(canvas.offsetTop * off);
var pixel = ctx.getImageData(x, y, 1, 1);
var data = pixel.data;
$("#color").val([pixel.data[0], pixel.data[1], pixel.data[2], pixel.data[3]].join(','));
//console.log("offset between", canvas.width, "and", canvas.offsetWidth, "is", off);
console.log(off, canvas.offsetWidth, canvas.width, x);
}
// target the button
var btn = $("#myBtn");
var modal = $("#myModal");
btn.click(function () {
modal.css("display", "block");
var canvas = document.getElementById("canvas");
canvas.addEventListener('mousemove', pick);
});
#myModal {
display: none;
/* Hidden by default */
position: fixed;
/* Stay in place */
z-index: 1;
/* Sit on top */
padding-top: 100px;
/* Location of the box */
left: 0;
top: 0;
width: 100%;
/* Full width */
height: 100%;
/* Full height */
overflow: auto;
/* Enable scroll if needed */
background-color: rgb(0, 0, 0);
/* Fallback color */
background-color: rgba(0, 0, 0, 0.4);
}
.modal-content {
background-color: #fefefe;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
canvas {
width: 100%;
/*margin-left: auto;
margin-right: auto;
display: block;*/
}
<form action="" method="post">
<label for="POST-name">Name:</label>
<input id="color" type="text">
</form>
<button id="myBtn">Open Color</button>
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<!-- Set height and width -->
<canvas id="canvas" width="1000" height="1000"></canvas>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.1.1.js" integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA=" crossorigin="anonymous"></script>
EDIT 1
Compensated for offsetLeft and offsetTop.

Multiple text shadows in 2d canvas

In CSS, I can chain multiple definitions in the text-shadow property to achieve effects such as glow:
.green-glow {
padding:20px 40px 40px;
font-family:'Georgia';
font-size:70px;
background-color:#000;
color: #fff;
text-shadow: 0 0 10px #fff, 0 0 20px #fff, 0 0 30px #fff, 0 0 40px #0f0, 0 0 70px #0f0, 0 0 80px #0f0, 0 0 100px #0f0, 0 0 150px #0f0;
}
<div class="green-glow">glow</div>
I would like to achieve similar effects when drawing text on a canvas element using CanvasRenderingContext2D.fillText but since shadow definitions are split among multiple properties (shadowBlur, shadowColor, etc.), it is not immediately obvious for me the adequate way to chain multiple shadows.
I can do multiple calls to CanvasRenderingContext2D.fillText, one for each defined shadow as the following snippet shows...
// get context
var ctx = document.querySelector('#test').getContext('2d');
// clear background to black
ctx.fillStyle = '#000'
ctx.fillRect(0, 0, 500, 150);
// common font attributes
ctx.font = "70px Georgia";
ctx.fillStyle = 'white';
// apply multiple shadows
ctx.shadowColor = '#fff';
ctx.shadowBlur = 10;
ctx.fillText('glow', 50, 90);
ctx.shadowBlur = 20;
ctx.fillText('glow', 50, 90);
ctx.shadowBlur = 30;
ctx.fillText('glow', 50, 90);
ctx.shadowColor = '#0f0';
ctx.shadowBlur = 40;
ctx.fillText('glow', 50, 90);
ctx.shadowBlur = 70;
ctx.fillText('glow', 50, 90);
ctx.shadowBlur = 80;
ctx.fillText('glow', 50, 90);
ctx.shadowBlur = 100;
ctx.fillText('glow', 50, 90);
ctx.shadowBlur = 150;
ctx.fillText('glow', 50, 90);
canvas {
width: 500px;
height: 150px;
}
<canvas id="test" width="500" height="150"></canvas>
... and even though it doesn't quite look the same to me, it would be good enough for my purposes. But I am wondering about possible performance issues caused by those multiple calls to fillText and whether there is a more appropriate way to apply multiple text shadows on a canvas.
Thanks!

Circle marker with three different border colors in Google Maps API

I have this CSS for a circle with one border color:
m = new MarkerWithLabel({
position: pos,
map: map,
labelContent: txt,
labelAnchor: new google.maps.Point(18, 18),
labelClass: "circle",
icon: "/i/t.png"
});
.circle {
border: 6px solid #ffd511;
border-radius: 30px;
-moz-border-radius: 30px;
-webkit-border-radius: 30px;
-khtml-border-radius: 30px;
width: 30px;
height: 18px;
line-height: 20px;
padding: 12px 6px;
text-align: center;
}
<div class="circle">17</div>
It looks like this:
How should I change the CSS to have three border colors - as on the clock:
from 0 to 4 color #1
from 4 to 8 color #2
from 8 to 12 color #3
As in this answer of my previous question:
svg{width:30%;height:auto;}
<svg viewbox="0 0 10 10">
<defs>
<circle id="circle" cx="5" cy="5" r="4" stroke-width="0.5" fill="transparent" />
</defs>
<use xlink:href="#circle" stroke="pink" stroke-dasharray="0,2.09,8.38,30" />
<use xlink:href="#circle" stroke="green" stroke-dasharray="0,10.47,8.38,30" />
<use xlink:href="#circle" stroke="orange" stroke-dasharray="2.09,16.75,6.3" />
</svg>
Required
The circle element is a marker shown in Google Maps API v3, so I am unable to use SVG.
Also another solution is to use an image:
.circle {
background: url('circle.png') no-repeat;
width: 58px;
height: 58px;
line-height: 20px;
text-align: center;
}
It looks like there is solution to do it with CSS as Marker for Google Maps API.
So I managed to create an image, and use this as background for Marker class .circle:
.circle {
background: url('circle.png') no-repeat;
width: 58px;
height: 58px;
line-height: 20px;
text-align: center;
}
You could do use of canvas, something like this will do it:
<canvas id="myCanvas" width="578" height="250"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var context2 = canvas.getContext('2d');
var context3 = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = 1.5 * Math.PI;
var endAngle = 0.15 * Math.PI;
var counterClockwise = false;
//1st arc
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
context.lineWidth = 10;
// line color
context.strokeStyle = '#FFA325';
context.stroke();
//second arc
startAngle=endAngle;
endAngle=0.85 * Math.PI;
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
// line color
context.strokeStyle = '#FFBEC9';
context.stroke();
//third arc
startAngle=endAngle;
endAngle=1.5 * Math.PI;
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
// line color
context.strokeStyle = '#007F1B';
context.stroke();
</script>
Hope it helps ,HERE you can find a link to a codepen, Thanks

Categories