creating a curved overlay between sections. - javascript

Hey guys i have the below design to create
Now i usually use a image in such a situation ,but was just wondering if this was possible in any other way I.E. maybe canvas ? I have just started learning canvas , so i can't say for certain.
FIDDLE HERE
HTML:
<div class='bnr'></div>
<div class='main'></div>
CSS:
.bnr {
height: 35vh;
background: #990853;
}
.main {
background: #fff;
height: 80vh;
}
Now how do i add those curved lines apart from using an image ?
Thank you.

<body onload="draw();">
<canvas id="canvas" width="985px" height="300px" ></canvas>
</body>
<script>
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(10,10);
ctx.lineTo(985,10);
ctx.lineTo(985,245);
ctx.quadraticCurveTo(965,270,965,280);
ctx.quadraticCurveTo(920,130,640,150);
ctx.quadraticCurveTo(530,160,350,190);
ctx.quadraticCurveTo(210,220,10,190);
ctx.lineTo(10,10);
ctx.stroke();
ctx.strokeStyle="#FFF";
ctx.fillStyle = "green";
ctx.fill();
ctx.beginPath();
ctx.moveTo(10,10);
ctx.lineTo(985,10);
ctx.lineTo(985,220);
ctx.quadraticCurveTo(965,230,955,255);
ctx.quadraticCurveTo(920,130,640,135);
ctx.quadraticCurveTo(510,140,350,170);
ctx.quadraticCurveTo(190,200,10,160);
ctx.lineTo(10,10);
ctx.stroke();
ctx.strokeStyle="#FFF";
ctx.fillStyle = "#990853";
ctx.fill();
ctx.beginPath();
ctx.arc(805, 150, 50, 0, 2 * Math.PI);
ctx.stroke();
ctx.strokeStyle="#FFF";
ctx.fillStyle = "#FFF";
ctx.fill();
ctx.beginPath();
ctx.arc(805, 150, 45, 0, 2 * Math.PI);
ctx.stroke();
ctx.strokeStyle="#FFF";
ctx.fillStyle = "#ce758b";
ctx.fill();
}
}
</script>
That how it looks with the previous code :

You can use canvas for obtain exaclty what you want. Use fill for background color and curve.
You can learn more about canvas:
canvas : http://www.w3schools.com/html/html5_canvas.asp
curve : http://www.w3schools.com/tags/canvas_beziercurveto.asp and http://www.w3schools.com/tags/canvas_quadraticcurveto.asp
fill : http://www.w3schools.com/tags/canvas_fill.asp
a lot of tutorial : http://www.html5canvastutorials.com/
Try my demo:
https://jsfiddle.net/pjxgLkm7/2/
Or
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.moveTo(0,0);
ctx.bezierCurveTo(0,50,20,50,200,0);
ctx.fillStyle = "#990853";
ctx.fill();
ctx.strokeStyle = '#990853';
ctx.stroke();
<canvas id="myCanvas" style="width:100%"></canvas>

Related

rotation problem in javascript animation using canvas

I'm trying to make a circle around another circle except that each turn the circles are not recreated in the same place so it doesn't work.
function init(){
ctx.globaleCompositeOperation = 'destination-over';
ctx.clearRect(0,0,innerWidth,innerHeight);
ctx.translate(800,400);
[enter image description here][1]
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.arc(0,0,110,0,Math.PI*2);
ctx.stroke();
ctx.closePath();
ctx.rotate(0.1*Math.PI/180);
ctx.beginPath();
ctx.arc(100,100,10,0,Math.PI*2);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
requestAnimationFrame(init);
}
init();
this is what it gives:
when i want that :
It works for me if I do two things.
Mend the typo which has an extra e in globaleCompositeOperation
And I sort of guess at what you have set innerWidth and innerHeight to. Are these set somewhere?
If you could put up a snippet with everything in it to make it work that might help. I can’t make a snippet as I am on a touch only device I’m afraid.
Here’s my code
<canvas id='c'></canvas>
<script>
function init(){
ctx.globalCompositeOperation = 'destination-over';
ctx.clearRect(0,0,1024,768);
ctx.translate(0,0);
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.arc(0,0,110,0,Math.PI*2);
ctx.stroke();
ctx.closePath();
ctx.rotate(0.1*Math.PI/180);
​
ctx.beginPath();
ctx.arc(100,100,10,0,Math.PI*2);
ctx.fillStyle = "blue";
ctx.fill();
ctx.closePath();
​
requestAnimationFrame(init);
}
let c= document.getElementById('c');
let ctx = c.getContext('2d');
init();
</script>

How can I get the "outline" of a Path stroke, and get the points to create a filled Path shape?

I want to retrieve the corresponding points to a 'outlinestroke' and save it as a Shape, instead of a "path with a stroke"
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.lineWidth = 12;
ctx.lineCap = 'round'
ctx.quadraticCurveTo(20, 100, 200, 20);
ctx.stroke();
</script>
</body>
</html>
This is the result of the code:
But I want to have the Outline of this stroke, and turn it into a Path and give it a stroke.
The fill should be transparent.
And only have a small outline.
Is there a way to "trace or convert" the stroke to a outline path to get the following result:
And if this is not possible:
Before drawing, to use the given points to define the shape of a path.
Here is what I tried:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var width = 12;
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.lineWidth = width;
ctx.quadraticCurveTo(20, 100, 200, 20);
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = 1;
ctx.fillStyle = "#ccc";
ctx.moveTo(20-width/2, 270);
ctx.quadraticCurveTo(20-width/2, 350+width/2, 200-width/2, 270+width/2);
ctx.lineTo(200-width/2, 270-width/2);
ctx.quadraticCurveTo(20+width/2, 350-width/2, 20+width/2, 270-width/2);
ctx.lineTo(20-width/2, 270);
ctx.fillStyle = "#999";
ctx.fill();
ctx.stroke();
ctx.closePath();
Which results in the following:
There are no API features to turn a strokes outline into a path.
You can however use a composite operation to create the inner transparency.
Example
Creating outline using globalCompositeOperation = "destination-out";
The gradient is just to show it is transparent.
const OUTLINE_WIDTH = 1; // in pixels
var ctx = canvas.getContext("2d");
ctx.lineWidth = 22;
ctx.lineCap = 'round'
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.quadraticCurveTo(20, 100, 200, 20);
ctx.stroke();
ctx.globalCompositeOperation = "destination-out";
ctx.lineWidth = 22 - OUTLINE_WIDTH * 2;
ctx.stroke();
ctx.globalCompositeOperation = "source-over"; // restore default
canvas {
border:1px solid #aaa;
background: linear-gradient(90deg, rgba(180,255,224,1) 0%, rgba(169,169,255,1) 100%);
}
<canvas id="canvas"></canvas>

Canvas: Zooming and Panning

I am struggling to make this canvas drawing to zoom in and out and panning it. There are some examples with panning and zooming images but my case is different and I don't know what or how should I do it in my case cause it is not images. I would appreciate any tips or any library that you could suggest?
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
canvas{border:#666 1px solid;}
</style>
<script type="application/javascript" language="javascript">
window.onload=draw;//execute draw function when DOM is ready
function draw(){
//assign our canvas element to a variable
var canvas=document.getElementById('canvas1');
//create the html5 context object to enable draw methods
var ctx=canvas.getContext("2d");
ctx.beginPath();
ctx.arc(150, 200, 20, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.moveTo(150,200);
ctx.lineTo(230,75);
ctx.stroke();
ctx.beginPath();
ctx.arc(230, 75, 20, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.moveTo(230,75);
ctx.lineTo(300,200);
ctx.stroke();
ctx.beginPath();
ctx.arc(300,200, 20, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.moveTo(300,200);
ctx.lineTo(150,200);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(300,200);
ctx.lineTo(225,300);
ctx.stroke();
ctx.beginPath();
ctx.arc(225,300, 20, 0, 2 * Math.PI);
ctx.fill();
//fillStyle (r, g, b, alpha)
//ctx.fillStyle = "rgba(0,200,0,1)";
//fillRect (X, Y, Width, height)
//ctx.fillRect(36,10,220,120);
}
</script>
</head>
<body>
<center>
<canvas id="canvas1" width="800" height="600" ></canvas>
</body>
</html>
This is a screenshot of my drawing that I am trying to make it zoom in mouse cursor:
canvas drawing
Panzoom (https://github.com/timmywil/panzoom) says that it supports panning and zoom basically any HTMLElement, including a canvas:
Panzoom uses CSS transforms to take advantage of hardware/GPU
acceleration in the browser, which means the element can be anything:
an image, a video, an iframe, a canvas, text, WHATEVER.
If you're okay with buttons instead of "drag to pan", you can use translate method for panning. You can also use save() and restore() methods or following approach. Here's what I used in similar situation, but I've used buttons:
<html>
<head>
<script>
window.onload = function() {
scale = 1;
canvas = document.getElementById("canvas"); //Replace with id of your canvas
ctx = canvas.getContext("2d");
ctx.translate(150, 75);
drawcanvas();
}
function drawcanvas() {
ctx.beginPath();
//call to function(s) which draws necessary things
//..
//..
drawarrow(ctx);
ctx.stroke();
}
function clearcanvas() {
let current_transform = ctx.getTransform();
ctx.setTransform(1.1, 0, 0, 1.1, 0, 0);
ctx.clearRect(0, 0, canvas.width*scale, canvas.height*scale);
ctx.setTransform(current_transform);
}
function zoomin() {
clearcanvas();
scale = 1.1;
ctx.scale(scale, scale);
drawcanvas();
}
function zoomout() {
clearcanvas();
scale = 1.0/1.1;
ctx.scale(scale, scale);
drawcanvas();
}
function moveleft() {
clearcanvas();
ctx.translate(-10, 0);
drawcanvas();
}
function moveright() {
clearcanvas();
ctx.translate(10, 0);
drawcanvas();
}
</script>
</head>
<body>
<canvas id="c" class="container h-75" style="border: solid 1px blue"></canvas><br />
<button onclick="zoomin()" class="btn btn-dark">+</button>
<button onclick="zoomout()" class="btn btn-dark">-</button>
<button onclick="moveleft()" class="btn btn-dark"><-</button>
<button onclick="moveright()" class="btn btn-dark">-></button>
</body>
</html>
EDIT: I found better solution for panning problem, check this question and it's accepted answer.

Overwrite drawn over canvas when drawing transparent shapes

I can't see that this had been posted already, so here goes.
Let's say i draw 2 squares on the canvas.
var c = document.getElementById('test'), ctx = c.getContext('2d');
ctx.fillStyle = "rgba(0,0,255,0.5)";
ctx.beginPath();
ctx.moveTo(25, 0);
ctx.lineTo(50, 50);
ctx.lineTo(0, 50);
ctx.lineTo(25, 0);
ctx.fill();
ctx.fillStyle = "rgba(255,0,0,0.5)";
ctx.beginPath();
ctx.moveTo(50, 0);
ctx.lineTo(75, 50);
ctx.lineTo(25, 50);
ctx.lineTo(50, 0);
ctx.fill();
This produces this image:
If i change globalAlpha to 0.5, i get this:
However, i want to produce this:
As in, all pixels are transparent and any images under it will appear, but the pixels created by the red triangle will overwrite the existing blue triangle where it is drawn.
And ctx.globalComposisteOperation doesn't seem to help in this instance due to it also factoring the transparency and the fact i want to keep both squares.
Is there any way to do this with current methods?
Use Compositing to clear the red triangle before drawing it.
Using compositing is slightly better than clipping because you don't have to clear the clip. Clearing a clip requires saving the entire context state and then restoring that context state -- many properties involved. Compositing just requires changing 1 property forth and back.
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
// fill the blue rect
ctx.fillStyle = "rgba(0,0,255,0.5)";
ctx.beginPath();
ctx.moveTo(25, 0);
ctx.lineTo(50, 50);
ctx.lineTo(0, 50);
ctx.lineTo(25, 0);
ctx.fill();
// define the red rect path
ctx.beginPath();
ctx.moveTo(50, 0);
ctx.lineTo(75, 50);
ctx.lineTo(25, 50);
ctx.lineTo(50, 0);
// clear the red rect path using compositing
ctx.globalCompositeOperation='destination-out';
ctx.fillStyle='black';
ctx.fill();
ctx.globalCompositeOperation='source-over';
// fill the red rect
ctx.fillStyle = "rgba(255,0,0,0.5)";
ctx.fill();
body{ background-color:white; }
#canvas{border:1px solid red; }
<canvas id="canvas" width=512 height=512></canvas>
Layers
Do it the photoshop way and create layers to do the work for you. Creating a layer (second canvas) is no more trouble than loading an image. You can create dozens and have no problem and it makes this type of work easy.
First create a second canvas (layer)
// canvas is original canvas
var layer = document.createElement("canvas");
layer.width = canvas.width; // same size as original
layer.height = canvas.height;
var ctx1 = layer.getContext("2d");
Then draw your triangles on the second canvas with alpha = 1;
var tri = (x,c)=>{
ctx1.fillStyle = c;
ctx1.beginPath();
ctx1.moveTo(25 + x, 0);
ctx1.lineTo(50 + x, 50);
ctx1.lineTo(0 + x, 50);
ctx1.closePath();
ctx1.fill();
}
tri(0,"#00f");
tri(25,"#f00");
Then just draw that layer on top of the canvas you are working on with the alpha value you want.
ctx.globalAlpha = 0.5;
ctx.drawImage(layer,0,0);
If you don't need the extra layer delete the canvas and context by dereferencing them.
ctx1 = undefined;
layer = undefined;
Or you can keep the layer , and make another layer for the background and mix them in real time to get the FX just right
//
var canvas = document.createElement("canvas");
document.body.appendChild(canvas);
var ctx = canvas.getContext("2d");
var layer = document.createElement("canvas");
layer.width = canvas.width; // same size as original
layer.height = canvas.height;
var ctx1 = layer.getContext("2d");
var tri = (x,c)=>{
ctx1.fillStyle = c;
ctx1.beginPath();
ctx1.moveTo(25 + x, 0);
ctx1.lineTo(50 + x, 50);
ctx1.lineTo(0 + x, 50);
ctx1.fill();
}
tri(0,"#00f");
tri(25,"#0f0");
tri(50,"#f00");
ctx.globalAlpha = 0.5;
ctx.drawImage(layer,0,0);
layer = ctx1 = undefined;
You can clear the area for the second rectangle before drawing it.
var c = document.getElementById('game'),
ctx = c.getContext('2d');
ctx.globalAlpha = 0.5;
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, 50, 50);
// Clear the extra bit of the blue rectangle
ctx.clearRect(25, 25, 25, 25);
ctx.fillStyle = "red";
ctx.fillRect(25, 25, 50, 50);
<canvas id="game" width="320" height="240"></canvas>
I would honestly suggest just changing the colors and avoid using an alpha.
var c = document.getElementById('game'),
ctx = c.getContext('2d');
ctx.fillStyle = "#8080FF";
ctx.fillRect(0, 0, 50, 50);
ctx.fillStyle = "#ff8080";
ctx.fillRect(25, 25, 50, 50);
<canvas id="game" width="320" height="240"></canvas>
var c = document.getElementById('test'), ctx = c.getContext('2d');
ctx.save();
ctx.fillStyle = "rgba(0,0,255,0.5)";
ctx.beginPath();
ctx.moveTo(25, 0);
ctx.lineTo(50, 50);
ctx.lineTo(0, 50);
ctx.lineTo(25, 0);
ctx.fill();
ctx.fillStyle = "rgba(255,0,0,0.5)";
ctx.beginPath();
ctx.moveTo(50, 0);
ctx.lineTo(75, 50);
ctx.lineTo(25, 50);
ctx.lineTo(50, 0);
ctx.clip();
ctx.clearRect(0, 0, 100, 100);
ctx.fill();
ctx.restore();
Just use clip() to take the current path, clear everything in there with clearRect, then draw the path as normal.
#markE is right, use compositing instead of clipping (really heavy).
However, his solution will only work if you've drawn everything with an rgba color. Maybe I read your question wrongly, but if you're going from an opaque shape and want to make it transparent, then you should rather use the copy gCO and the globalAlpha property.
This will have less performance impact since drawImage is faster than fill, and will allow you to perform a fade-out effect ; but it really depends on your needs.
var ctx = c.getContext('2d');
// initial blue
ctx.fillStyle = "#0000FF";
ctx.beginPath();
ctx.moveTo(25, 0);
ctx.lineTo(50, 50);
ctx.lineTo(0, 50);
ctx.lineTo(25, 0);
ctx.fill();
setTimeout(function drawRed() {
ctx.fillStyle = "#FF0000";
ctx.beginPath();
ctx.moveTo(50, 0);
ctx.lineTo(75, 50);
ctx.lineTo(25, 50);
ctx.lineTo(50, 0);
ctx.fill();
}, 500);
btn.onclick = function makeItTransparent() {
// if we weere to make this into an animation, we would set it only once
ctx.globalCompositeOperation = 'copy';
ctx.globalAlpha = .8;
// draw the canvas on itself
ctx.drawImage(c, 0, 0);
// once again, in an animation we won't reset this to default
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = 'source-over';
};
/* checkboard background */
canvas {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYlWNgYGBowIKxgqGgcJA5h3yFAOI3GQFqqi5ZAAAAAElFTkSuQmCC");
}
<canvas id="c"></canvas>
<button id="btn">make it transparent</button>

Linewidth spreading to all canvas objects

I've got this problem where I add a lineWidth to one canvas-object and then all canvas-objects in the same canvas gets the same lineWidth. For example:
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.moveTo(20,20);
ctx.lineTo(20,100);
ctx.lineTo(70,100);
ctx.lineWidth = 10;
ctx.closePath();
ctx.stroke();
ctx.fillStyle="red";
ctx.fill();
ctx.beginPath();
ctx.arc(200, 100, 50, 0, 2 * Math.PI);
ctx.fillStyle="blue";
ctx.fill();
ctx.stroke();
ctx.closePath();
</script>
</body>
</html>
How do I make the lineWidth only apply to one object?
Change the lineWidth line to be:
var defaultLineWidth = ctx.lineWidth;
ctx.lineWidth = 10;
Then in the second drawing action, add this:
ctx.lineWidth = defaultLineWidth;
It's state based. You have to reset lineWidth later on to the value you want for the next path.
Live Demo
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.moveTo(20,20);
ctx.lineTo(20,100);
ctx.lineTo(70,100);
ctx.lineWidth = 10;
ctx.closePath();
ctx.stroke();
ctx.fillStyle="red";
ctx.fill();
ctx.lineWidth = 3; //this
ctx.beginPath();
ctx.arc(200, 100, 50, 0, 2 * Math.PI);
ctx.fillStyle="blue";
ctx.fill();
ctx.stroke();
ctx.closePath();
I would try to set
ctx.lineWidth = 0;
before calling ctx.stroke() again.

Categories

Resources