Stacking canvases and transparency - html5-canvas

Two canvases one on top of the other as below. The second canvas cvs should be transparent since by default all canvases are transparent and I do a clearRect just to make sure.
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<canvas id="myCanvas" width="578" height="430"></canvas>
<canvas id="cvscan" style="display:none"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var cvs = document.getElementById('cvscan');
var cvsctx = cvs.getContext('2d');
context.save();
context.clearRect(0, 0, 578, 430);
context.fillStyle = 'gray';
context.fillRect(0, 0, 578, 430);
context.beginPath();
context.moveTo(0, 0);
context.lineWidth = 3;
context.lineTo(578, 430);
context.strokeStyle = '#444444';
context.stroke();
context.moveTo(578, 0);
context.lineTo(0, 430);
context.stroke();
cvs.width = 200;
cvs.height = 200;
cvsctx.clearRect(0, 0, cvscan.width, cvscan.height);
var curimg = cvsctx.getImageData(0, 0, cvs.width, cvs.height);
context.putImageData(curimg, 50, 50);
context.restore();
</script>
</body>
</html>
I believe the second canvas should be transparent and (since there's nothing drawn in it) invisible -- but it's filled with white. What am I missing?
UPDATE this is what I see -- I believe the white box should not be there.
Here is the image

The canvas with id="cvscan" is being cleared, which means the image data is being set to 0 for all, rgba(0,0,0,0), values.
Next, that image data is being painted onto the canvas with id="myCanvas", updating the pixel on "myCanvas" to zero.
So, the canvas ("myCanvas") is now transparent at the painted location, and is seen as white, because the background of the body is now showing.
To validate the results a test was run logging the data of the image, and then updating bgcolor to red.
(see photos)

Related

why doesn't d3-geo-zoom pan correctly for more then 1 canvas elements on the page?

When panning in the first canvas, things work like expected. When panning in the second canvas, it doesn't work like expected. I expected both to work the same. The second globe spins rapidly after a little bit of panning, the first globe keeps the cursor on the same coordinates.
https://codepen.io/tonytrupe/pen/jOqjGvE
class UI {
constructor(canvas) {
var width = canvas.width,
height = canvas.height;
//set projection type here, geoOrthographic, geoWinkel3
var projection = d3
.geoWinkel3()
//.scale((Math.min(width, height)) / 2)
.translate([width / 2, height / 2])
//.rotate([0,0,0])
.fitExtent(
[
[6, 6],
[width - 6, height - 6]
],
{
type: "Sphere"
}
);
draw();
//this.addZoomPan = function () {
d3
.geoZoom()
.northUp(true)
.projection(projection)
.onMove(draw)(canvas);
//};
function draw() {
var ctx = canvas.getContext("2d");
var path = d3.geoPath().context(ctx).projection(projection);
// Store the current transformation matrix
ctx.save();
// Use the identity matrix while clearing the canvas
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Restore the transform
ctx.restore();
var border = {
type: "Sphere"
};
ctx.beginPath();
path(border);
ctx.strokeStyle = "#000";
ctx.stroke();
var lat = 45;
var lon = 45;
var graticule = d3.geoGraticule().step([lat, lon]);
ctx.beginPath();
path(graticule());
ctx.strokeStyle = "#000";
ctx.stroke();
}
}
}
//var one = new UI(document.getElementById("one"));
//var two = new UI(document.getElementById("two"));
var three = new UI(document.getElementById("three"));
html
<html>
<script src="//d3js.org/d3.v6.js"></script>
<script src="//d3js.org/d3-geo.v2.min.js"></script>
<script src="//d3js.org/d3-geo-projection.v3.min.js"></script>
<script src="//unpkg.com/d3-geo-zoom"></script>
<!--removing all but the last canvas element makes things work as expected-->
<canvas id="one" class="canvas" width="320" height="200"></canvas>
<canvas id="two" class="canvas" width="320" height="200"></canvas>
<canvas id="three" class="canvas" width="320" height="200"></canvas>
</html>
https://github.com/vasturiano/d3-geo-zoom/issues/12
It previously wasn't getting pointer location relative to the node element. Now it is.
const pointers = d3Pointers(zoomEv, nodeEl);
https://github.com/vasturiano/d3-geo-zoom/blob/86da0d98f267a838a4715abec60e4a278ace2121/src/geoZoom.js#L59

How To: Draw (HTML5) Video into (Custom) Canvas Shape with KinecticJS

Here's my example: http://jsbin.com/urofan/7/edit
I would like to draw the video into a custom shape, not in a rectangle shape, is that possible right now? (PS: The shape is draggable) All I found in StackO or in the web are for rectangular drawings...
In the future, the shape will be a circle with adjustable radius and position (draggable and resizable).
Thanks for your help.
Allan.
You can contain an image (video frame grab) into a path using the clip method.
First define the path you want the video frame to be contained in.
Note that you don’t have to do fill/stroke.
context.beginPath();
context.moveTo(200, 50);
context.lineTo(420, 80);
context.lineTo(250, 400);
context.lineTo(40, 80);
context.closePath();
Next, create a clipping path from your defined path.
Everything drawn after this will be clipped inside your clipping path.
context.clip();
Finally, draw a frame grab of the video and drawImage into the clipping path.
The frame grab will only appear inside your clipping path.
context.drawImage(0,0,canvas.width,canvas.height);
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/aMW74/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.1.min.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 500,
height: 500
});
var layer = new Kinetic.Layer();
stage.add(layer);
var img=document.createElement("img");
img.onload=function(){
drawClippedImage(img);
}
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/KoolAidMan.png";
function drawPathForClipping(context){
context.beginPath();
context.moveTo(200, 50);
context.lineTo(420, 80);
context.lineTo(250, 400);
context.lineTo(40, 80);
context.closePath();
}
function drawClippedImage(img){
var shape = new Kinetic.Shape({
id: 'shape',
drawFunc: function(canvas) {
var context = canvas.getContext();
// define the path that will be used for clipping
drawPathForClipping(context);
// make the last path a clipping path
context.clip();
// draw a clipped image (frame grab)
context.drawImage(img,0,0,img.width,img.height);
// styling, draw the clip path for real as a border
drawPathForClipping(context);
canvas.stroke(this);
},
stroke: 'black',
strokeWidth: 4,
draggable: true
});
// add the shape shape to the layer
layer.add(shape);
layer.draw();
}
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>

Animate (Oscillation) custom drawn shape on Canvas

Good day.
I am looking for abit of advice. Before judging, please take note I am new to coding, with only a few weeks of experience.
I am trying to make the cloud shape I have draw onto the canvas, animated, using JavaScript. (Please see link below to the type of animation I am looking to achieve.) I have searched everywhere for how to achieve this, but it seems all the links either deal with an actual image, or a rectangle, and not a custom drawn shape. So my question is this, is it possible to do such an animation on a custom shape, and, if not, what is the best way to go about it to achieve said desired effect.
<!DOCTYPE HTML>
<HTML>
<head>
<style>
body {
margin: 100px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="Canvas" width="700" height="600" style="border:1px solid #005BAB;"></canvas>
<script>
var canvas = document.getElementById('Canvas');
var context = canvas.getContext('2d');
// gradients
var grd = context.createRadialGradient(550, 150, 25, 500, 200, 400);
grd.addColorStop (0, '#0586f8');
grd.addColorStop (1, '#015baa');
// blue block shadow
context.shadowColor = '#999';
context.shadowBlur = 35;
context.shadowOffsetX = 8;
context.shadowOffsetY = 8;
context.globalCompositeOperation = 'source-over';
context.beginPath();
context.fill();
// blue block
context.beginPath();
context.moveTo(50, 35);
context.lineTo(50, 525);
context.lineTo(550, 525);
context.lineTo(550, 35);
context.closePath();
context.lineWidth = 0;
context.strokeStyle = '#999';
context.fillStyle = grd;
context.fill();
// cloud shadow
context.shadowColor = '#232323';
context.shadowBlur = 20;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.beginPath();
context.globalAlpha = 0.9;
context.fill();
// cloud drawing
context.beginPath();
context.moveTo(172, 180);
context.bezierCurveTo(145, 180, 120, 234, 185, 240);
context.lineTo(375, 240);
context.bezierCurveTo(495, 234, 405, 110, 382, 168);
context.bezierCurveTo(440, 85, 280, 60, 325, 120);
context.bezierCurveTo(320, 42, 190, 60, 200, 120);
context.bezierCurveTo(120, 100, 140, 200, 170, 180);
context.lineWidth = 1;
context.fillStyle = 'white';
context.fill();
context.strokeStyle();
context.lineCap = 'round';
context.lineJoin = 'round';
context.stroke();
</script>
</body>
</HTML>
http://www.html5canvastutorials.com/advanced/html5-canvas-oscillation-animation/
You could create another canvas with javascript:
var cloud = document.createElement('canvas');
cloud.width = <width of the cloud>;
cloud.height = <height of the cloud>;
Then draw your cloud onto that canvas. You should adjust your coordinates so that the top left of the cloud's bounding box is at point (0, 0). This way the cloud canvas is only as big as it needs to be.
Then you can treat your cloud just like you would an image.
context.drawImage(cloud, 0, 0);

set offset/position of polygon to rotate

I'm trying to perform a crop of a background image with different shapes.
The objective is to move/rotate around the polygons, crop the background with the shape of the polygon, somehow plot the cropped image over the polygon and save the cropped polygon as a new image.
So far I can drag and rotate(arrow keys) the polygons over the canvas.
First, I'm having problems rotating the polygons: I want them to rotate on its center.
And second, cropping the background with the polygon shape.
Here's a link to a jsbin: http://jsbin.com/efoqav/1/edit
Any ideas?
Thanks.
Here’s how to use your Kinetic polygon to clip a background image
First, use the background image as a fillPattern in your Kinetic polygon. Make the fill non-repeating and offset the pattern by the x/y position of the polygon:
var hexagon = new Kinetic.RegularPolygon({
x: 50,
y: 50,
sides: 6,
radius: 50,
fillPatternImage: img,
fillPatternRepeat: "no-repeat",
fillPatternOffset: [-50,-50],
stroke: 'black',
strokeWidth: 3,
draggable: true
});
Then when th user drags the polygon (or you move it with keystrokes), reposition the fillPatternOffset by the current position of the polygon. Essentially, the fill inside the polygon will “follow” the dragging polygon.
hexagon.on('dragmove', function() {
var position=this.getAbsolutePosition();
var x=position.x;
var y=position.y
this.setFillPatternOffset(x,y);
layer.draw();
});
To rotate your polygon around its center (centerX,centerY), do this trigonometry to each of your Kinetic Polygon Points and then reset the shape with yourKineticPolygon.setPoints.
// if the rotation angle is degrees, you must first convert it to radians:
var radianAngle = degreeAngle * Math.PI/180;
// modify each of your polygon points like this
var dx = centerX – pointX;
var dy = centerY – pointY;
var radius = Math.sqrt( dx*dx + dy*dy);
var rotatedX = centerX + radius * Math.cos(radianAngle);
var rotatedY = centerY + radius * Math.cos(radianAngle);
And to save the stage to an image, you can use stage.toDataURL like this:
// hide the background since you're just interested in the clip
background.hide();
// this saves the stage (your clipped polygon) to an image url
stage.toDataURL({
// just like an image object, you need an onload-ish callback
callback: function(dataUrl){
// testing -- put the image in an html img
var imgElement=document.getElementById("saved");
imgElement.src=dataUrl;
// reshow the background
background.show();
}
});
Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/eQYB8/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.1.min.js"></script>
<style>
body{ background-color: ivory; padding:20px;}
img{border:1px solid red;}
</style>
<script>
$(function(){
// this just generates a sample image
var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");
var count=0;
canvas.width=300;
canvas.height=300;
for(var x=0;x<10;x++){
for(var y=0;y<10;y++){
ctx.beginPath();
ctx.arc(x*30+15,y*30+15,15,0,Math.PI*2,false);
ctx.fillText(count++,x*30+11,y*30+18);
ctx.stroke();
}
}
var img=new Image();
img.onload=function(){
draw();
}
img.src=canvas.toDataURL();
function draw(){
var stage = new Kinetic.Stage({
container: 'container',
width: 300,
height: 300
});
var layer = new Kinetic.Layer();
stage.add(layer);
var background = new Kinetic.Image({
x: 0,
y: 0,
image: img,
width: 300,
height: 300,
opacity:.25
});
layer.add(background);
var hexagon = new Kinetic.RegularPolygon({
x: 50,
y: 50,
sides: 6,
radius: 50,
fillPatternImage: img,
fillPatternRepeat: "no-repeat",
fillPatternOffset: [-50,-50],
stroke: 'black',
strokeWidth: 3,
draggable: true
});
layer.add(hexagon);
layer.draw();
hexagon.on('dragmove', function() {
var position=this.getAbsolutePosition();
var x=position.x;
var y=position.y
this.setFillPatternOffset(x,y);
layer.draw();
});
$("#save").click(function(){
background.hide();
stage.toDataURL({
callback: function(dataUrl){
var imgElement=document.getElementById("saved");
imgElement.src=dataUrl;
background.show();
}
});
});
}
}); // end $(function(){});
</script>
</head>
<body>
<button id="save">Save</button><br><br>
<p>Drag the Polygon to your desired clip</p><br>
<div id="container"></div><br>
<p>Saved results without background</p>
<img id="saved" width=300 height=300/>
</body>
</html>

Canvas with a image to jpeg

I want to get a .jpg on a canvas, add a rectangle and a String, which is working very good. After that I want to create a jpg out of the canvas, which works fine but the jpg of the canvas does only show the rectangle and the String. Quick Code-example - i know its a ugly canvas - just testing ;)
<!DOCTYPE html>
<html>
<body>
<canvas id="meinCanvas" width="600" height="600" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
</body>
<script type="text/javascript">
var canv = document.getElementById("meinCanvas");
var context = canv.getContext("2d");
context.fillStyle = "#000000";
context.fillRect(10,10, 200, 100);
var img = new Image();
img.onload = function() {
context.drawImage(img, 300, 300);
};
img.src="one.jpg";
context.font = "bold 12px sans-serif";
context.fillText("test", 500, 500);
imgsr = canv.toDataURL("image/jpeg");
document.write('<img src="' +imgsr +'"/>');
</script>
</html>
}
In the upper part (the canvas) the img is shown properly, but in the .jpeg beneth it the img is not shown. Help would be great. thanks.
Image is not loaded yet when you save it.
Put the toDataUrl in img.onload or link it to an event or timer

Resources