I need to draw a shape then add shadow but shadow is over the filled color I need it to be under it .. I can't explain the situation well so here is an example on jsfiddle
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
context.closePath();
context.lineWidth = 5;
context.fillStyle = "#8ED6FF";
context.strokeStyle = "#0000ff";
context.shadowColor = "#000000";
context.shadowBlur = 2;
context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.fill();
context.stroke();
http://jsfiddle.net/j8u8p/ thx
http://jsfiddle.net/j8u8p/11/
Note: All I did was rearrange the context calls and add in a globalCompositeOperation
p.s. this looks nicer: http://jsfiddle.net/j8u8p/13/
p.p.s this is tweaked because you moaned about the gap: http://jsfiddle.net/j8u8p/16/
Related
I'm a newbie in canvas drawing. I want to draw the PV string model and the direction of flow of electrons into <canvas> tag.
This is what I want to achieve, redrawing the lines from the following direction:
How do I initially set the animation location, and do I need to update it via setTimeout?
Here is what I try so far:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
// drawing code here
/* First Row */
ctx.fillStyle = "rgb(2,150,224, 1)";
ctx.fillRect(50, 50, 50, 50);
ctx.fillStyle = "rgb(2,150,224, 1)";
ctx.fillRect(110, 50, 50, 50);
ctx.fillStyle = "rgb(188,12,50, 1)";
ctx.fillRect(170, 50, 50, 50);
ctx.fillStyle = "rgb(2,150,224, 1)";
ctx.fillRect(230, 50, 50, 50);
ctx.fillStyle = "rgb(2,150,224, 1)";
ctx.fillRect(290, 50, 50, 50);
/* Second Row */
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(50, 150, 50, 50);
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(110, 150, 50, 50);
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(170, 150, 50, 50);
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(230, 150, 50, 50);
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(290, 150, 50, 50);
/* Paths */
ctx.beginPath();
ctx.lineWidth = "3";
ctx.strokeStyle = "rgb(34,177,76, 1)";
ctx.moveTo(0, 75);
ctx.lineTo(400, 75);
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = "10";
ctx.strokeStyle = "rgb(34,177,76, 1)";
ctx.moveTo(400, 75);
ctx.lineTo(400, 175);
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = "3";
ctx.strokeStyle = "rgb(34,177,76, 1)";
ctx.moveTo(0, 175);
ctx.lineTo(400, 175);
ctx.stroke();
} else {
// canvas-unsupported code here
}
/* canvas {
border: 1px solid #d3d3d3;
} */
<canvas id="myCanvas" width="400" height="400">
Your browser does not support the HTML5 canvas tag.</canvas>
Any help would be appreciated!
There are many ways to animate this; here's my approach (excerpt; see
JSFiddle for full code):
var lerp = (a, b, t) => a + t * (b - a);
var speed = 0.01;
var time = 0;
var visited = [];
var points = [
{
from: { x: 0, y: 75 },
to: { x: 395, y: 75 }
},
{
from: { x: 395, y: 75 },
to: { x: 395, y: 175 }
},
{
from: { x: 395, y: 175 },
to: { x: 0, y: 175 }
}
];
/* Paths */
ctx.lineWidth = 3;
ctx.strokeStyle = "rgb(34, 177, 76, 1)";
(function update() {
if (points.length) {
visited.push({
x: lerp(points[0].from.x, points[0].to.x, time),
y: lerp(points[0].from.y, points[0].to.y, time)
});
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBoxes(ctx);
ctx.beginPath();
ctx.moveTo(visited[0].x, visited[0].y)
visited.forEach(e => ctx.lineTo(e.x, e.y));
ctx.stroke();
time += speed;
if (time >= 1) {
time = 0;
points.shift();
}
requestAnimationFrame(update);
}
})();
The idea is to keep a data structure of all the turning points, then lerp along the path, drawing a line along the way. Use an easing function instead of lerp if you prefer a more "modern"-looking animation; easing is usually easier to implement and may result in removal of some code (for example, no need to keep track of starting points and time).
Last minor note--your original code was cutting off the line at the right edge of the canvas, so I took the liberty of using 395 instead of 400 for the drawing width.
I am trying to write a text on a canvas. Following is the code :
HTML
<canvas id="scaleChart" width="1500" height="500"></canvas>
JS
var scaleCtx = document.getElementById("scaleChart").getContext("2d");
scaleCtx.fillStyle = 'rgba(40, 220, 140, 1)';
scaleCtx.fillRect(0, 0, 800, 200);
scaleCtx.fillStyle = 'Black';
scaleCtx.font = '20px Calibri';
scaleCtx.fillText = ('00:00', 100, 50);
But no text is appearing. What wrong am I doing? Here is the Fiddle
Simple typo. Last line of JS should not have an equal sign in it.
var scaleCtx = document.getElementById("scaleChart").getContext("2d");
scaleCtx.fillStyle = 'rgba(40, 220, 140, 1)';
scaleCtx.fillRect(0, 0, 800, 200);
scaleCtx.fillStyle = 'Black';
scaleCtx.font = '20px Calibri';
scaleCtx.fillText('00:00', 100, 50);
I am trying to implement print function based on the layout I created below.
<html>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<script>
function draw_bordered_rect(context, x, y, w, h) {
var colors = ['grey','red','black','green','orange','purple','yellow'];
context.rect(x, y, w, h);
context.fillStyle = "green";
context.fill();
context.lineWidth = 3;
context.strokeStyle = "lightblue";
context.stroke();
canvasContext.font = '25pt Arial';
canvasContext.textAlign = 'center';
canvasContext.fillStyle = colors[x];
//canvasContext.fillStyle = "black";
canvasContext.fillText('ACTIVITY 1',canvas.width/2-2, 56);
}
window.onload = function() {
canvas = document.getElementById('gameCanvas');
canvasContext = canvas.getContext('2d');
canvasContext.fillStyle = 'white';
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
base_image = new Image();
base_image.src = 'http://jacobian.xyz/draw/pic1.png';
base_image.onload = function(){
canvasContext.drawImage(base_image, 250, 80);
}
bases_image = new Image();
bases_image.src = 'http://jacobian.xyz/draw/e.png';
bases_image.onload = function(){
canvasContext.drawImage(bases_image, 20, 400);
}
bases1_image = new Image();
bases1_image.src = 'http://jacobian.xyz/draw/f.png';
bases1_image.onload = function(){
canvasContext.drawImage(bases1_image, 250, 550);
}
bases2_image = new Image();
bases2_image.src = 'http://jacobian.xyz/draw/g.png';
bases2_image.onload = function(){
canvasContext.drawImage(bases2_image, 450, 545);
}
bases3_image = new Image();
bases3_image.src = 'http://jacobian.xyz/draw/h.png';
bases3_image.onload = function(){
canvasContext.drawImage(bases3_image, 350, 545);
}
draw_bordered_rect(canvasContext, 0, 0, 790, 70);
draw_bordered_rect(canvasContext, 0, 540, 790, 70);
canvasContext.fillStyle = 'grey';
canvasContext.fillRect(20, 150, 40, 40);
canvasContext.fillStyle = 'orange';
canvasContext.fillRect(20, 200, 40, 40);
canvasContext.fillStyle = 'purple';
canvasContext.fillRect(20, 250, 40, 40);
canvasContext.fillStyle = 'magenta';
canvasContext.fillRect(20, 300, 40, 40);
canvasContext.fillStyle = 'red';
canvasContext.fillRect(70, 150, 40, 40);
canvasContext.fillStyle = 'green';
canvasContext.fillRect(70, 200, 40, 40);
canvasContext.fillStyle = 'blue';
canvasContext.fillRect(70, 250, 40, 40);
canvasContext.fillStyle = 'yellow';
canvasContext.fillRect(70, 250, 40, 40);
canvasContext.fillStyle = 'black';
canvasContext.fillRect(70, 300, 40, 40);
}
</script>
</html>
so that when they click on the print button in the picture then the print dialog would come up.
I think the print function is like this.
function printPage()
{
window.print();
}
any help would be appreciated though.
Just make the buttons not part of the canvas. Have them part of normal html <a> or <button> tags that you styled.
Then add the the print function to an onclick event on those buttons/links.
That way you can also hide them in your CSS from printing. So they won't show up on the printed end result.
I created a html page. this page displayed circle with svg path and also a png file included in this page. now i want to download this page as pdf file. so please help me.
I used javascript codes but not satisfied.
<html> <script src="http://parall.ax/parallax/js/jspdf.js"></script>
<canvas id="myCanvas" width="578" height="200"></canvas>
**<img src="bodysmall.png" id="m">**
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// draw cloud
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
context.closePath();
context.lineWidth = 5;
context.fillStyle = '#8ED6FF';
context.fill();
context.strokeStyle = '#0000ff';
context.stroke();
// only jpeg is supported by jsPDF
var imgData = canvas.toDataURL("image/jpeg", 1.0);
var pdf = new jsPDF();
pdf.addImage(imgData, 'JPEG', 0, 0);
pdf.save("download.pdf");
</script>
So I have made basic drawings with html5 canvas and the basic shapes you can create have parameters to position the whole shape, below I center a circle centerX and centerY by taking the window size and dividing by 2.
context.beginPath();
context.globalCompositeOperation = 'destination-out';
context.arc(centerX, centerY, radius, Math.PI*2, false);
context.fill();
context.closePath();
The above drawing is nice and centered but now that I am playing with the bezier curve I can't find anything on the web that suggests how to center it.
// some arbitrary example
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.fill();
context.globalCompositeOperation = 'destination-out';
context.closePath();
I wrote up a fiddle so there is something to work with JSFIDDLE. Below is the code pasted directly from my fiddle.
var canvas = document.getElementById("c");
var context = canvas.getContext("2d");
canvas.width = $(window).width();
canvas.height = $(window).height();
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.fillStyle = '#333';
context.fillRect(0, 0, canvas.width, canvas.height);
context.closePath();
// custom shape (weird shape lol)
context.beginPath();
context.globalCompositeOperation = 'destination-out';
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.fill();
context.closePath();
context.globalCompositeOperation = 'source-over';
}
draw();
Here's one method to accurately center your group of cubic Bezier curves
A Demo: http://jsfiddle.net/m1erickson/6GZmp/
Step#1. Use De Casteljau's algorithm to plot points along each curve in your group of curves.
// De Casteljau's algorithm which calculates points along a cubic Bezier curve
// plot a point at interval T along a bezier curve
// T==0.00 at beginning of curve. T==1.00 at ending of curve
// Calculating 100 T's between 0-1 will usually define the curve sufficiently
function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
return({x:x,y:y});
}
// cubic helper formula at T distance
function CubicN(T, a,b,c,d) {
var t2 = T * T;
var t3 = t2 * T;
return a + (-a * 3 + T * (3 * a - a * T)) * T
+ (3 * b + T * (-6 * b + b * 3 * T)) * T
+ (c * 3 - c * 3 * T) * t2
+ d * t3;
}
Step#2. Determine the bounding box of the curve-group by getting the minX,maxX,minY,maxY of the points you plotted in #1. And use max-min to determine the width and height of the curves group.
var curvesWidth = maxX - minX;
var curvesHeight = maxY - minY;
Step#3. Calculate the offset needed in order to center your curves-group.
var offsetX=(canvas.width/2-curvesWidth/2)-curvesLeft;
var offsetY=(canvas.height/2-curvesHeight/2)-curvesTop;
Step#4. Knowing the offsets, you can use context.translate to draw your centered curves.
context.save();
context.translate(offsetX,offsetY);
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.fill();
context.restore();
I don't know if there's a quick way of doing it. My attempt works like this:
you check each point on the x axis and compare it to the other points, if it is the most left or the most right store their position in a variable, otherwise do nothing. Once you have those points you know the width of the whole path and you can calculate an offset value to place it inside the center (because you know the canvas width). Then just add that offset value to the points coordinates and you're good:
http://jsfiddle.net/jonigiuro/8jsw9/4/
var canvas = document.getElementById("c"); var context = canvas.getContext("2d");
canvas.width = $(window).width(); canvas.height = $(window).height();
var centerX = canvas.width / 2; var centerY = canvas.height / 2;
var bezierSteps = [
[130, 100, 130, 150, 230, 150],
[250, 180, 320, 180, 340, 150],
[420, 150, 420, 120, 390, 100]
];
var mostLeft = 2000; var mostRight = 0;
findCenter();
function findCenter() {
for (var i = 0; i < bezierSteps.length; i++) {
for (var p = 0; p < bezierSteps.length; p+=2) {
mostLeft = bezierSteps[i][p] < mostLeft ? bezierSteps[i][p] : mostLeft;
mostRight = bezierSteps[i][p] > mostRight ? bezierSteps[i][p] : mostRight;
}
}
console.log(mostLeft, mostRight) } var offset = (canvas.width - mostLeft - mostRight) / 2;
console.log(offset)
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.fillStyle = '#333';
context.fillRect(0, 0, canvas.width, canvas.height);
context.closePath();
// custom shape (weird shape lol)
context.beginPath();
context.globalCompositeOperation = 'destination-out';
context.moveTo(170 + offset, 80);
for (var i = 0, l = bezierSteps.length ; i < l ; i++) {
context.bezierCurveTo(bezierSteps[i][0] + offset,bezierSteps[i][1],bezierSteps[i][2] + offset,bezierSteps[i][3],bezierSteps[i][4] + offset,bezierSteps[i][5])
}
//context.bezierCurveTo(130, 100, 130, 150, 230, 150);
//context.bezierCurveTo(250, 180, 320, 180, 340, 150);
//context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.fill();
context.closePath();
context.globalCompositeOperation = 'source-over';
}
draw();
sorry for the dirty code..