I need to add a gradient to a canvas. I have tested all solutions, but nothing works.
Original code:
ctx.strokeStyle = params.wheelBorderColor;
ctx.lineWidth = params.wheelBorderWidth;
ctx.font = params.wheelTextFont;
ctx.clearRect(0, 0, 500, 500);
var text = null,
i = 0,
totalJoiner = pplLength;
var width = ctx.measureText(text).width + blur * 2;
for (i = 0; i < totalJoiner; i++) {
text = pplArray[i];
var angle = startAngle + i * arc;
ctx.fillStyle = colorCache.length > totalJoiner ? colorCache[i] : genHex(text);
ctx.beginPath();
// ** arc(centerX, centerY, radius, startingAngle, endingAngle, antiClockwise);
ctx.arc(250, 250, params.outterRadius, angle, angle + arc, false);
ctx.arc(250, 250, params.innerRadius, angle + arc, angle, true);
ctx.stroke();
ctx.fill();
ctx.save();
ctx.fillStyle = params.wheelTextColor;
ctx.translate(250 + Math.cos(angle + arc / 2) * params.textRadius, 250 + Math.sin(angle + arc / 2) * params.textRadius);
ctx.rotate(angle + arc / 2 + Math.PI / 1);
ctx.fillText(text, -ctx.measureText(text).width / 2, 6);
ctx.restore();
ctx.closePath();
}
drawArrow();
And i add this code for gradiant and the fill() is already sent to original code
var grd = ctx.createLinearGradient(0.000, 150.000, 300.000, 150.000);
// Add colors
grd.addColorStop(0.000, 'rgba(0, 0, 0, 1.000)');
grd.addColorStop(1.000, 'rgba(255, 255, 255, 1.000)');
// Fill with gradient
ctx.fillStyle = grd;
ctx.fill();
The genHex() is:
color = "#666"; colorCache.push('#'+color); return '#'+color;"
Any guidance would be helpful.
Are you drawing a rectangle within your context? Try something like this:
var canvas = document.getElementById('test-canvas');
var ctx = (canvas !== null ? canvas.getContext('2d') : null);
var grd = (ctx !== null ? ctx.createLinearGradient(0.000, 150.000, 300.000, 150.000) : null);
if (grd) {
ctx.rect(0, 0, canvas.width, canvas.height);
grd.addColorStop(0.000, 'rgba(0, 0, 0, 1.000)');
grd.addColorStop(1.000, 'rgba(255, 255, 255, 1.000)');
ctx.fillStyle = grd;
ctx.fill();
}
I have posted a working example at JSFiddle: http://jsfiddle.net/briansexton/e6rC3/
Related
In the graphic the idea was to put a shadow only on the white circle, but it looks like the shadow effect was applied to the text, which shouldn't happen.
Canvas:
<canvas class="gradient" id="canvas_gradient_chart" height="70"></canvas>
Javascript:
drawChartGradient(canvas, radian, height, metric) {
const rect = canvas.getBoundingClientRect();
const ctx = canvas.getContext("2d");
canvas.width = rect.width;
canvas.height = height;
ctx.beginPath();
const centerY = canvas.height / 2;
const centerX = this.positionXChart(canvas.width, metric, 20);
ctx.arc(centerX, centerY, radian, 0, Math.PI * 2, false);
ctx.fillStyle ="#ffffff";
ctx.filter = 'drop-shadow(2px 2px 5px rgba(0,0,0,0.6))';
ctx.fill();
ctx.font = 'bold 14pt sans-serif';
ctx.textAlign = 'center';
ctx.strokeStyle ='#ffffff'
ctx.stroke();
ctx.fillStyle ="#622BCF"; // <-- Text colour here
ctx.shadowBlur=0;
ctx.shadowColor='transparent';
ctx.fillText(`${metric ? metric : 0}`, centerX, centerY+8);
//ctx.globalCompositeOperation = 'destination-over';
ctx.globalCompositeOperation = 'source-over';
canvas.addEventListener('mousemove', (e) => {
const relativeCoodinates = {
x:parseInt(`${centerX}`),
y:parseInt(`${centerY}`),
r:radian
}
});
ctx.globalCompositeOperation = 'destination-over';
ctx.save();
ctx.restore();
}
positionXChart(size, number, distance) {
return size/(200 + distance) * (parseInt(`${number}`) + 100 + distance / 2);
}
Canvas would render:
You have to reset the filter or the same will be applied to all elements:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter#value
See working sample:
const canvas = document.getElementById("canvas")
const ctx = canvas.getContext("2d")
ctx.beginPath()
ctx.arc(50, 50, 40, 0, Math.PI * 2)
ctx.fillStyle = "#ffffff"
ctx.filter = 'drop-shadow(2px 2px 5px)'
ctx.fill()
ctx.beginPath()
ctx.font = 'bold 30pt sans-serif'
ctx.textAlign = 'center'
ctx.textBaseline = "middle"
ctx.fillStyle = "#622BCF" // <-- Text colour here
ctx.filter = 'none'
ctx.fillText("80", 50, 50)
<canvas id="canvas" ></canvas>
And the textBaseline = "middle" I think does a good job at keeping the text centered
so I am experimenting with 2d drawings in Javascript and what I am trying to do is change the ctx.fillStyle (which is the drawing colour) and change it to another colour when the URL changes.
Any help would be greatly appreciated. Here is a part of my code:
The codepen link for the animation: https://codepen.io/LudovicTomlo/pen/PEWEwJ
window.draw = setInterval(function() {
ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
ctx.fillRect(0, 0, c.width, c.height);
ctx.fillStyle = "#00ff00";
ctx.font = font_size + "px Sawarabi Gothic";
if(location.pathname.endsWith("/401?e=1")) {
ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
ctx.fillRect(0, 0, c.width, c.height);
ctx.fillStyle = "#ff0000";
ctx.font = font_size + "px Sawarabi Gothic";
}
for(var i = 0; i < rain.length; i++) {
// random character from the set
var text = chars[Math.floor(Math.random()*chars.length)];
ctx.fillText(text, i*font_size, rain[i]*font_size);
if(rain[i]*font_size > c.height && Math.random() > 0.975) {
rain[i] = 0;
}
//incrementing Y coordinate
rain[i]++;
}
}, speed);
}
In the W3 Schools HTML Canvas Clock drawing tutorial, the clock numbers are translated around the canvas using a static multiplier (.85, shown below).
ctx.translate(0, -radius*0.85);
If you didn't want to use the hardcoded/static .85 value to position the numeral, how would you find the correct position using Sin, or Cos, or other means?
I think here is the answer:
function drawNumerals() {
var numerals = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ],
angle = 0,
numeralWidth = 0;
numerals.forEach(function(numeral) {
angle = Math.PI/6 * (numeral-3);
numeralWidth = context.measureText(numeral).width;
context.fillText(numeral,
canvas.width/2 + Math.cos(angle)*(HAND_RADIUS) - numeralWidth/2,
canvas.height/2 + Math.sin(angle)*(HAND_RADIUS) + FONT_HEIGHT/3);
});
}
You just have to edit it to your needs.
I found it on Github Gist Draw circle with clock numbers
Seems to scale up correctly when i tried.
Are you removing or omitting the height attribute on the canvas element like this?
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas"
style="background-color:#333">
</canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90
drawClock();
function drawClock() {
drawFace(ctx, radius);
drawNumbers(ctx, radius);
}
function drawFace(ctx, radius) {
var grad;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2*Math.PI);
ctx.fillStyle = 'white';
ctx.fill();
grad = ctx.createRadialGradient(0,0,radius*0.95, 0,0,radius*1.05);
grad.addColorStop(0, '#333');
grad.addColorStop(0.5, 'white');
grad.addColorStop(1, '#333');
ctx.strokeStyle = grad;
ctx.lineWidth = radius*0.1;
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, radius*0.1, 0, 2*Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
}
function drawNumbers(ctx, radius) {
var ang;
var num;
ctx.font = radius*0.15 + "px arial";
ctx.textBaseline="middle";
ctx.textAlign="center";
for(num = 1; num < 13; num++){
ang = num * Math.PI / 6;
ctx.rotate(ang);
ctx.translate(0, -radius*0.85);
ctx.rotate(-ang);
ctx.fillText(num.toString(), 0, 0);
ctx.rotate(ang);
ctx.translate(0, radius*0.85);
ctx.rotate(-ang);
}
}
</script>
</body>
</html>
The code determines the height it should use for the clock from the elements actual dimensions. If you dont constrain the height and width it will look wrong.
If you see you can double the size of the clock by modifying the height and width attributes of the canvas
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas" height="800px" width="800px"
style="background-color:#333">
</canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90
drawClock();
function drawClock() {
drawFace(ctx, radius);
drawNumbers(ctx, radius);
}
function drawFace(ctx, radius) {
var grad;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2*Math.PI);
ctx.fillStyle = 'white';
ctx.fill();
grad = ctx.createRadialGradient(0,0,radius*0.95, 0,0,radius*1.05);
grad.addColorStop(0, '#333');
grad.addColorStop(0.5, 'white');
grad.addColorStop(1, '#333');
ctx.strokeStyle = grad;
ctx.lineWidth = radius*0.1;
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, radius*0.1, 0, 2*Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
}
function drawNumbers(ctx, radius) {
var ang;
var num;
ctx.font = radius*0.15 + "px arial";
ctx.textBaseline="middle";
ctx.textAlign="center";
for(num = 1; num < 13; num++){
ang = num * Math.PI / 6;
ctx.rotate(ang);
ctx.translate(0, -radius*0.85);
ctx.rotate(-ang);
ctx.fillText(num.toString(), 0, 0);
ctx.rotate(ang);
ctx.translate(0, radius*0.85);
ctx.rotate(-ang);
}
}
</script>
</body>
</html>
For one of my application i am creating circular time range selector widget.I have created the clock dial using html canvas.I need help to select time range by touch and drag on the dial as shown in the imageCircular clock dial. When clicked on the "Add" button, the previous selection should be cleared. Next time i should be able to set new range. this continues. The range value should be stored in a variable. It should work on the mobile device. Your help would be appreciated. http://codepen.io/harish_s/pen/ggpoBq
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = 180;
drawClock();
function drawClock() {
drawFace(ctx, radius);
drawNumbers(ctx, radius);
}
function drawFace(ctx, radius) {
var grad;
ctx.beginPath();
ctx.strokeStyle = "rgb(207,207,207)";
ctx.arc(0, 0, radius, 0, 2*Math.PI);
ctx.lineWidth = 60;
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, 150, 0, 2*Math.PI);
ctx.fillStyle = "rgb(243,244,244)";
ctx.fill();
ctx.beginPath();
ctx.arc(0, 0, 50, 0, 2*Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
ctx.font = '25pt Calibri';
ctx.fillStyle = 'white';
ctx.fillText('SET', -25, 10);
}
function drawNumbers(ctx, radius) {
var ang;
var num;
ctx.font = radius*0.20 + "px arial";
ctx.fillStyle = '#000';
ctx.textBaseline="middle";
ctx.textAlign="center";
for(num = 1; num < 13; num++){
ang = num * Math.PI / 6;
ctx.rotate(ang);
ctx.translate(0, -radius*1);
ctx.rotate(-ang);
ctx.fillText(num.toString(), 0, 0);
ctx.rotate(ang);
ctx.translate(0, radius*1);
ctx.rotate(-ang);
}
}
#canvas{
position: absolute;
width: 50%;
left: 35%;
top:5%;
}
<canvas id="canvas" width="1000" height="500">
</canvas>
I am attempting to animate an emoticon that was previously drawn in canvas. I am attempting to do a draw and clear using frames following a tutorial but am not getting results. I have 6 frames of the emoticon coded and am unsure how to include this within the code. This is what I have so far:
<!DOCTYPE html>
<html>
<head>
<title>Adding Animation</title>
<style>
canvas {
border: 3px #CCC solid;
}
</style>
</head>
<body>
<div id="container">
<canvas id="myCanvas" height="1200" width="900"></canvas>
</div>
<script>
var mainCanvas = document.querySelector("#myCanvas");
var mainContext = mainCanvas.getContext("2d");
var canvasWidth = mainCanvas.width;
var canvasHeight = mainCanvas.height;
function drawCircle() {
mainContext.clearRect(0, 0, canvasWidth, canvasHeight);
// color in the background
mainContext.fillStyle = "#EEEEEE";
mainContext.fillRect(0, 0, canvasWidth, canvasHeight);
// draw the circle
ctx.beginPath();
ctx.strokeStyle = "000000";
ctx.lineWidth = 5;
ctx.fillStyle = "yellow";
ctx.arc(600, 450, 150, 0, Math.PI * 2, true);
ctx.stroke();
ctx.closePath();
ctx.fill();
//The smile
ctx.beginPath();
ctxstrokeStyle = "black";
ctx.lineWidth = 2;
ctx.arc(600, 475, 75, .1 * Math.PI, Math.PI * .9, false)
ctx.stroke();
ctx.closePath();
//The eyes
//Left
ctx.save();
ctx.scale(0.65, 1);
ctx.beginPath();
ctx.arc(850, 405, 40, 0 * Math.PI, Math.PI * 2, false);
ctx.fillStyle="black";
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore();
//Right
ctx.save();
ctx.scale(0.65, 1);
ctx.beginPath();
ctx.arc(1000,405,40, 0*Math.PI, Math.PI*2, false);
ctx.fillStyle="black";
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore()
}
drawCircle();
</script>
</body>
</html>
I am unsure if I am even on the right track as I have a difficult time with animation. Does anyone have any suggestions they can give me guidance on?
You have 2 names for the context: mainContext & ctx.
Change it to a single name and your face is "smiley" ! :-)
...
To animate:
Use a requestAnimationFrame loop to change the scaleY value in scale(scaleX,scaleY) over time.
Here's annotated code and a Demo:
var mainCanvas = document.querySelector("#myCanvas");
var ctx = mainCanvas.getContext("2d");
var canvasWidth = mainCanvas.width;
var canvasHeight = mainCanvas.height;
ctx.translate(-425,-275);
drawCircle(1);
// global var to hold pct the left eye is open
// 1==fully open, 0==fully closed
var scaley=1;
var direction=-1;
// request 1 animate() loop
requestAnimationFrame(animate);
function animate(time){
// draw smiley with the specified eye openness
drawCircle(scaley);
scaley+=.02*direction;
if(scaley<0){
scaley=0;
direction=1;
}
if(scaley>1){
scaley=1;
direction=-1;
}
requestAnimationFrame(animate);
}
function drawCircle(scaleY) {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
// color in the background
ctx.fillStyle = "#EEEEEE";
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
// draw the circle
ctx.beginPath();
ctx.strokeStyle = "000000";
ctx.lineWidth = 5;
ctx.fillStyle = "yellow";
ctx.arc(600, 450, 150, 0, Math.PI * 2, true);
ctx.stroke();
ctx.closePath();
ctx.fill();
//The smile
ctx.beginPath();
ctxstrokeStyle = "black";
ctx.lineWidth = 2;
ctx.arc(600, 475, 75, .1 * Math.PI, Math.PI * .9, false)
ctx.stroke();
//The eyes
//Left
ctx.save();
// move the [0,0] origin to the left eye's centerpoint
ctx.translate(550,405);
// close the left eye by the specified scaleY
ctx.scale(0.65, scaleY);
ctx.beginPath();
// draw the left eye (arc) at 0,0 because
// we translated the origin to [550,405] earlier
ctx.arc(0, 0, 40, 0 * Math.PI, Math.PI * 2, false);
ctx.fillStyle="black";
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore();
//Right
ctx.save();
ctx.scale(0.65, 1);
ctx.beginPath();
ctx.arc(1000,405,40, 0*Math.PI, Math.PI*2, false);
ctx.fillStyle="black";
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.restore()
}
<canvas id="myCanvas" height="1200" width="900"></canvas>
You never declared a ctx variable.
Change all your mainContext by ctx and it should be working fine.