KonvaJS, masking instead of clipFunc possible? - javascript

I'm using konvajs and need some help!
Assume that I need an image that's draggable inside a complex shape.
I wonder if it's possible to use masking with Konva.Group instead of clipFunc OR a way to convert a masking image to canvas-clip-path and use it with clipFunc!
Like this: Masking draggable

By default Konva supports only simple clip with rectangle shape and clipping with clipFunc where you can describe required path.
https://konvajs.github.io/docs/clipping/Clipping_Function.html
In both cases, clipping is defined as canvas paths, and you can't define clip here as an image.
But you can draw directly into the canvas with custom Konva.Shape.
const girafe = new Image();
girafe.onload = () => {
const img = new Image();
img.onload = () => {
const image = new Konva.Shape({
sceneFunc: (ctx) => {
ctx.drawImage(girafe, 0, 0);
ctx.globalCompositeOperation = 'source-in';
ctx.drawImage(img, 0, 0);
},
// (!) important
// for this case you need to define custom hit function
hitFunc: (ctx) => {
ctx.rect(0, 0, girafe.width, girafe.height);
ctx.fillStrokeShape(image);
},
draggable: true
});
layer.add(image);
layer.draw();
};
img.src = "http://i.imgur.com/kKjW3U4.png";
}
girafe.src = "http://i.imgur.com/fQX2P8S.png";
The output will be:
DEMO: http://jsbin.com/qahulidube/2/edit?js,output
Note: remember to define hitFunc because Konva hit detection will not work for such sceneFunc
Another two demos with other behaviors:
http://jsbin.com/huserozire/1/edit?js,output
http://jsbin.com/hawiricaqu/1/edit

Related

Canva image dont display the image sometime using drawImage() method? [duplicate]

This question already has an answer here:
CanvasContext2D drawImage() issue [onload and CORS]
(1 answer)
Closed 3 years ago.
I want just to draw an image on canva using drawImage() method .But it happen sometime that the image is not drawn . even when I use the onload event it still fail to display the image.
Before I ask my question I want just to precise that the image is drawn somtimes and not drawn sometime .So what is the reason of the this problem and how can I tackle or fix it .
let imagez = new Image();
imagez.src="photo/run.png";
context.drawImage(imagez,10,10,50,60); // it does not draw the image always. why?
I expect the image to be drawn whenever I refresh the page
That most likely happens because the drawImage() method is called before the actual image is completely loaded.
Wait for it to finish loading before you call drawImage().
var canvas = document.createElement("canvas");
document.body.appendChild(canvas);
canvas.width = 400;
canvas.height = 300;
var context = canvas.getContext("2d");
let imagez = new Image();
imagez.onload = function() {
context.drawImage(imagez, 10, 10, 50, 60);
}
imagez.src = "https://picsum.photos/400/300";
For this you have to wait for the image(s) to load into memory before they are available to draw to the canvas.
A simple loadIMAGE() function to achieve this might look something like this...
function loadIMAGE(path, x, y, w, h) {
var img = new Image();
img.addEventListener("load", function(e) {
// 'this' === the image Object
context.drawImage(this, x, y, w, h);
}, !1);
img.src = path;
}
// USAGE
loadIMAGE("photo/run.png", 10, 10, 50, 60);
It is important that the event-Handling function is defined before the src value is assigned.
Hope that helped :)
You are attempting to draw the image without knowing if it was successfully loaded...
Here is a working sample, using the onload event
const canvas = document.getElementById("gameArea");
context = canvas.getContext("2d");
let imagez = new Image();
imagez.onload = function () {
context.drawImage(imagez, 10, 10, 50, 60);
}
imagez.src = "https://upload.wikimedia.org/wikipedia/commons/e/e2/3D_Gyroscope.png";
<canvas id=gameArea></canvas>

How do I use an image to fill a layer in OpenLayers?

I'm using OpenLayers to draw a map, and I'd like to fill the polygon that describes a country with a photo from that country. I know I can pass a CanvasPattern to ol.style.Fill's color, but I don't know to generate an image.
Here's my code, and a JSfiddle with a full example: http://jsfiddle.net/07366L44/5/
function getPhoto() {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var photo = new Image();
photo.src = 'http://i.imgur.com/C6PL9tB.jpg';
return context.createPattern(photo, 'repeat');
}
I think it's because the photo is loaded async. Other examples create the pattern in the photo.onload method but I don't know how to return that.
Optimally I'd like to return a canvas which I can animate or update later with other photos, but I'll settle for just a single static image per country!
You'll have to set your style's fill color in the image's onload handler.
/**
* #param {ol.style.Style} style Style to set the pattern on.
*/
function setPattern(style) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var photo = new Image();
photo.onload = function() {
canvas.width = photo.width;
canvas.height = photo.height;
var pattern = context.createPattern(photo, 'repeat');
style.getFill().setColor(pattern);
}
photo.src = 'http://i.imgur.com/C6PL9tB.jpg';
}
Note that the fill's color needs to be set before the style function is called, so you cannot call the setPattern function in the style function. It's better to create the style before loading the layer.

Is it possible to select the same part of an image as a filler in each vector in a canvas?

I hae an array of triangles that i draw like this, I'm trying to create a kaleidoscope-like pattern, so I would like to use the same portion of the image in each triangle. When I apply a pattern like this, the triangle works more like a cropping mask, exposing all of the image instead.
draw = () => {
triangles.forEach((t) => {
const pattern = c.createPattern(image, 'no-repeat')
c.beginPath();
c.moveTo(t.center.x, t.center.y)
c.lineTo(t.right.x, t.right.y)
c.lineTo(t.left.x, t.left.y)
c.fillStyle = pattern
c.fill();
})
}
fill()
image.src = 'http://www.allers.se/wp-content/uploads/2011/04/kungen-ny-700x525.jpg'
image.onload = function() {
draw()
};
http://jsfiddle.net/cagpum6z/

Simple ball animation HTML5 using requestAnimationFrame

I am just starting trying to make some animation using HTML5 and JavaScript.
Currently I have created a JavaScript class for the ball. It has an update function which should update the position of the ball and a draw function which should draw it:
/*global Vector*/
var Ball = (function () {
function Ball(pPostion) {
this.setPosition(pPostion);
}
Ball.prototype.getPosition = function () {
return this.mPosition;
};
Ball.prototype.setPosition = function (pPosition) {
this.mPosition = pPosition;
};
Ball.prototype.draw = function (pContext) {
pContext.save();
pContext.beginPath();
pContext.arc(100, 100, 20, 0, Math.PI * 2, true);
pContext.closePath();
pContext.fillStyle = '#ff0000';
pContext.stroke();
pContext.restore();
};
Ball.prototype.update = function () {
this.getPosition().add(new Vector(10, 0));
};
return Ball;
}());
In the my main section I have created the following method:
function ballGameLoop() {
ball.draw(mainContext);
ball.update();
requestAnimationFrame(ballGameLoop);
}
And when called, it does draw the ball but it doesn't seem to move at all. I don't have a specific type of way I want the ball to be animated, just any kind of movement would be good. Can anyone give any advice on where I may be going wrong?
From the looks of it, it seems you are just drawing an arc at the same coordinates over and over again (center at (100,100)).
Incorporating your Ball's position into this would be the way to make the render location dependent on the object's position. From what it seems, something along the lines of the following would give movement:
Ball.prototype.draw = function (pContext) {
var coordinates = this.getPosition();
pContext.save();
pContext.beginPath();
pContext.arc(coordinates.X, coordinates.Y, 20, 0, Math.PI * 2, true);
pContext.closePath();
pContext.fillStyle = '#ff0000';
pContext.stroke();
pContext.restore();
};
I'm of course assuming on how you setup the Vector object, so I'm guessing x and y can be accessed by (Vector).X and (Vector).Y respectively.
anyway just my approach at it.

Canvas pre rendering?

Is there any point in pre-rendering images on canvas?
An example,
var img; // Img object
var pre = document.createElement("canvas");
pre.width = img.width;
pre.height = img.height;
var precon = pre.getContext("2d");
precon.drawImage(img, 0, 0);
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
for(var i =0; i < 10000; ++i) {
ctx.drawImage(pre, Math.random() * canvas.width, Math.random() * canvas.height);
}
I don't see the point as you are still calling context.drawImage no matter what you do, unless the canvas api is faster drawing an image from a canvas object rather than image object?
Firstly, I must say that your example is not suitable to highlight the need and benefits of canvas pre-rendering.
I'll give you a better example were you need to draw multiple times something that requires heavy computation on a canvas.
Let's say you have this draw function :
function complexDraw(ctx){
ctx.drawImage(img, width, height);
// heavy computation goes here
// some transforms maybe
ctx.ctx.setTransform(-1, 0, 0, 1, 200, 200);
ctx.fillStyle = "rgba(100, 100, 255, 0.5)";
ctx.fillRect(50, 50, 100, 100);
//maybe draw another img/video/canvas
ctx.drawImage(anotherImg, width, height);
// ...
}
function draw(){
complexDraw(ctx);
}
Now let's say you want to show the current time on the canvas too. That means that we're going to add this at the bottom of our draw function :
function drawTime(ctx){
ctx.fillText(new Date().getTime(), 10, 50);
}
And now our draw function looks like this :
function draw(){
complexDraw(ctx);
drawTime(ctx);
}
Since you want to always show the current time, you need to call the draw function every second :
setInterval(draw, 1000);
This actually means that every second you are doing some heavy computation just to update a silly little text.
If only there could be a way to split the draw function and compute only the things that need computing (the ones that change)... but there is: say hello to canvas pre-rendering!
The key idea is to draw the part that doesn't change (and doesn't need to be re-computed) on a separate canvas - let's call it cacheCanvas - and just copy it's content on our app's canvas whenever we want to redraw stuff :
// suppose we have a `clone` function
var cacheCanvas = clone(canvas),
cacheCtx = cacheCanvas.getContext('2d');
// let's draw our complex stuff on the cacheCanvas
complexDraw(cacheCtx);
// modify our main `draw` function to copy the result of the `complexDraw`
// function, not to call it
function draw(){
ctx.drawImage(cacheCanvas, width, height);
drawTime();
}
And now we're basically redrawing the whole canvas each second, but we're not re-computing all the heavy work in complexDraw.
I just want to note that most of the canvas based games can't run at 60fps (redraw 60 times per second) without doing some performance boost with pre rendering or another technique called canvas layering (which is also worth looking into).

Categories

Resources