Kinetic color fill tween not working - javascript

Im trying to change the color of the target node on mouse over and am currently using this code:
layer.on('mouseenter', function(evt) {
var shape = evt.targetNode;
shape.moveTo(secondLayer);
stage.draw()
var tween = new Kinetic.Tween({
node: shape,
duration: 0.05,
scaleX: 1.5,
scaleY: 1.5,
fillRed: 255,
fillGreen: 102,
fillBlue: 0,
});
tween.play()
});
secondLayer.on('mouseout', function(evt) {
var shape = evt.targetNode;
var tween = new Kinetic.Tween({
node: shape,
duration: 0.05,
scaleX: 1,
scaleY: 1,
fillRed: 17,
fillGreen: 17,
fillBlue: 17,
onFinish: function() {
shape.moveTo(layer);
layer.draw();
}
});
tween.play();
});
The scale tween works fine however the color does not change at all. Not entirely sure what Im doing wrong.
Heres a jsfiddle of it:
http://jsfiddle.net/y2C3Z/5/

The 'fill' attribute that you set for the triangle has priority over fillRed, fillGreen, and fillBlue... so you would also have to set the color with those RGB attributes when creating the triangle.
From the official change log:
the color component API has changed a lot. fillR() has changed to
fillRed(), fillB() has changed to fillBlue(), etc. The same goes for
stroke and shadowColor components. The RGB() methods have been removed
because they have muddied up the API. i.e. fillRGB(), strokeRGB(), and
shadowColorRGB() have been removed. The components are now actual
attrs. the fill attr has priority over components. i.e. if you set
fill to 'blue' but you set the fillRed and fillGreen values, the fill
will resolve to blue.
Here is a working jsfiddle of your code using the latest version of Kinetic JS. Note that I also had to change evt.targetNode to evt.target.

Related

Text's `fill` color is overriden by `stroke` in Konva

I have some Konva Text node, whose fill attribute is set to black and stroke is set to some other color.
In my canvas it looks as expected. The problem happens when I convert the canvas to base64 image to download it as an image file - in that case the downloaded image looks like in the screenshot below:
(the canvas is on the left side, the right one is the downloaded image)
As you can see, the stroke color is applied to the text's own color as well.
I created a Codesandbox example with a Text node that has the same attributes as in my environment, here is how that node is created:
const text = new Konva.Text({
x: 26.330053300533024,
y: 128,
text: "Add a body text",
defaultText: "Add a body text",
fontSize: 22,
fontFamily: "Montserrat",
draggable: true,
name: "text",
fontStyle: "300",
id: "textkgrsl68w",
is_settings: true,
wrap: "word",
padding: 5,
fill: "black",
opacity: 1,
isPremium: false,
width: 183.5,
visible: true,
rotation: 0,
scaleX: 1,
scaleY: 1,
offsetX: 0,
offsetY: 0,
skewX: 0,
skewY: 0,
stroke: "rgba(255,0,0,1)",
strokeWidth: 3.75
});
As you can see, it has the same (incorrect) look - without the inline color. I played with fontSize in Codesandbox and when I set it to very big value (like 100), the text's inline color became visible.
I assumed it can be some ratio problem, but as we see on the screenshot, the text's size is similar in both canvas and downloaded image.
How can this be fixed, maybe there is some extra attribute that should also be set?
konva: 7.1.4
react-konva: 16.12.0-0
UPDATED:
You can use text.fillAfterStrokeEnabled(true); to draw fill over stroke.
Old answer:
By default Konva is drawing fill first then stroke. So it will be a text itself and then stroke around it (that goes overfill part).
Probably one-day Konva will support a different order, but at the current moment konva#7.1.4 can't do that.
As a workaround just use two Konva.Text instances. First for stroke, second for fill.
https://codesandbox.io/s/download-konva-text-node-with-stroke-as-base-64-image-forked-w0z4v

How to apply a filter to a shape with image fill in KonvaJS?

I'm using Konva.js to do some canvas animations. I have circle shapes, with an image fill, and would like to apply a color overlay/filter to the shape (RGBA).
This is how I'm creating the Shape object:
var konvaObject = new Konva.Circle({
x: 100,
y: 100,
radius: 300,
stroke: this.color,
strokeWidth: 6,
fillPatternRepeat: 'no-repeat',
});
// load the image into the shape:
var imageObj = new Image();
imageObj.onload = function () {
konvaObject.fillPatternImage(imageObj);
konvaObject.draw();
}
imageObj.src = 'www.demo.com/anImageName.png';
demo: http://jsbin.com/winugimeme/edit?js,output
The Docs outline an RGBA filter, however as far as I can tell it can only be applied to Konva.Image items.
Is there a way to re-work my above code so that I can apply filters to the shape object/fill image?
According to filter documentation, you have to cache shape before applying filters http://konvajs.github.io/api/Konva.Filters.html#RGBA
node.cache();
node.filters([Konva.Filters.RGBA]);
node.blue(120);
node.green(200);
node.alpha(0.3);
Note: jsbin demo will not work with this example as fill image should be CORS enabled (e.g. hosted on same domain).

Animating SVG line about endpoint with Snap.svg

I have the following code which when you click the gray semi-circle there are two animations that happen, I am very close to my intended outcome, however the line path animation animates about a point but that point seems to move at the end, I would like it to rotate about it's endpoint so that i doesn't move out of the circle that endpoint is in.
It is much clearer in the jsfiddle to see what I am talking about and the issue at hand.
** You have to click the gray circle to activate the animation **
console.clear();
var loop = "M31,201.1C16.6,118.8,69.1,40.5,150.7,26c32.5-5.8,64.5-1.6,93.7,14.5c59.1,32.6,88.4,94,77.1,159.1";
var pin = "M180.4,193.3c-1.8,0-3.5-0.9-4.4-2.6c-1.3-2.4-0.5-5.5,2-6.8L309.8,111c2.4-1.3,5.5-0.5,6.8, 2c1.3,2.4,0.5,5.5-2,6.8l-131.8,72.9C182.1,193.1,181.2,193.3,180.4,193.3z";
var circle_svg = "M-224.1,227.9c-5.1,5.1-5.1,13.4,0,18.5s13.4,5.1,18.5,0s5.1-13.4,0-18.5C-210.8,222.8-219,222.8-224.1,227.9z";
var loopLength = Snap.path.getTotalLength(loop);
console.log(loopLength);
var s = Snap();
circle = s.path({
path: loop,
fill: "gray",
stroke: "#c00",
strokeWidth: 0,
strokeLinecap: "round"
});
var g = s.gradient("l(0, 0, 1, 1)#80DFFE-#0CA5EE-#07A3EE");
circleOutline = s.path({
path: Snap.path.getSubpath(loop, 0, 0),
stroke: g,
fillOpacity: 0,
strokeWidth: 0,
strokeLinecap: "round"
});
circle_middle = s.path({
path: circle_svg,
stroke: "#000000",
fill: "#ffffff",
strokeWidth: 5,
});
pin_line = s.path({
path: pin,
fill: "#000000"
});
// +"t"+[translateX,translateY]
circle_middle.attr({
transform: "t" + [400, -65]
});
pin_line.attr({
transform: 'r-170,180,180'
});
circle.click(function(e) {
Snap.animate(0, loopLength,
function(step) { //step function
circleOutline.attr({
path: Snap.path.getSubpath(loop, 0, step),
strokeWidth: 25
});
}, // end of step function
800 //duration
); //Snap.animate
pin_line.animate({
transform: 'r30,180,180',
translate: '20, 20, 85, 85'
}, 1000);
}); //click the circle
svg {
height: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.4.1/snap.svg-min.js"></script>
So there was indeed an alignment issue, and I tried to fix that in Illustrator, then came back to your example, and realized how some of those transforms in the JS actually work, and was able to adjust them to finally look correct, but when I tried just adjusting the transforms using your paths, I couldn't get it right, even when applying t(ranslations) to the pin_line in addition to rotations. So it's either a combination of the paths needing to be replaced with some fine-tuning of that rotation points, or it's that I just don't fully understand how to work the snapsvg code. :) In any case, I got a fiddle working that incorporates some of my new path coordinates made in Illustrator and some changes to the JS: https://jsfiddle.net/14e107mt/4/ In addition to the paths changing, it comments out the translation of circle_middle's translation (since it's now aligned there by default), and changes the pin_line rotation coordinates to
pin_line.attr({ transform: 'r-170 176 172' });
and
pin_line.animate({ transform: 'r30 176 172' }, 1000 );
instead of 180 180.

KineticJS: How can I include custom canvas shapes in a toDataURL function

My problem started with the version 5 of KineticJS, before that it was not a problem. Native KineticJS shapes such as squares and circles can be saved to an image file using the stage.toDataURL function. But it doesn't work for non-Kinetic shapes drawn with normal canvas methods such as beginPath(); and canvas.fill(); (version 4 did this fine). The following code draws two rectangles, one red and one blue. The red is custom, the blue is a native kinetic rectangle.
<body>
<div id="container"></div>
<button id="save">
Save as image
</button>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.2.min.js"> </script>
<script>
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var box = new Kinetic.Rect({
x: 400,
y: 80,
width: 100,
height: 50,
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
layer.add(box);
stage.add(layer);
var canvas = layer.getCanvas().getContext('2d');
canvas.beginPath();
canvas.setAttr('strokeStyle', 'black');
canvas.setAttr('fillStyle', '#FF2222');
canvas.setAttr('lineWidth', 8);
canvas.rect(50,80,100,50);
canvas.stroke();
canvas.fill();
document.getElementById('save').addEventListener('click', function() {
stage.toDataURL({
callback: function(dataUrl) {
window.location.href = dataUrl;
}
});
}, false);
</script>
</body>
Both shapes appear, but only the blue rectangle appears in the image generated by the toDataURL function. The way they are drawn has changed in KineticJS 5, where you set attributes for fillStyle etc. so I'm thinking that may have something to do with it, or maybe the fact that the custom shape is added after the layer is added to the stage...
You are correct, between recent versions much has changed, and this has probably broken something in your drawing function.
You should consult the official docs on each item, but basically a custom shape has slightly updated properties... first of all "StrokeStyle" is no longer a valid property. Just use 'stroke'. Same thing with FillStyle.
Also -- 'dashArray' is no longer valid, now it's just 'dash' -- so I'm sure there are more things that changed that I'm not recalling... right, such as 'lineWidth' is now 'strokeWidth'...
Also -- the way you show or don't show strokes and fills has changed... yep, pretty much most of the way you used to do it has been changed slightly. 'drawFunc' is now 'sceneFunc' also...
var ctx = layer.getContext();
var customShape01 = new Kinetic.Shape({
sceneFunc: function(ctx) {
ctx.beginPath();
ctx.moveTo(162.1, 213.8);
ctx.bezierCurveTo(162.1, 213.8, 180.7, 215.3, 193.5, 214.5);
ctx.bezierCurveTo(205.8, 213.7, 221.8, 212.3, 222.8, 221.4);
ctx.bezierCurveTo(222.9, 221.7, 222.9, 222.0, 222.9, 222.3);
ctx.bezierCurveTo(222.9, 232.4, 204.6, 232.7, 192.0, 227.1);
ctx.bezierCurveTo(179.4, 221.5, 163.1, 213.8, 162.1, 213.8);
ctx.closePath();
ctx.fillStrokeShape(this);
},
id: 'customShape01',
fill: 'rgb(255, 0, 255)',
stroke: 'black',
strokeWidth: 2,
lineJoin: 'round',
dash: [5,5],
dashEnabled: 'true',
strokeEnabled: 'true'
});
check out a full working sample (you'll have to allow popups).
http://jsfiddle.net/axVXN/1/

KineticJS shape opacity

I need some assistance changing the opacity of a shape using KineticJS (5.0.0.).
In an mouse event, I want to change the opacity of the shape, which triggered the event. Whenever the shape is hovered, it gets visible ( opacity 1.0 ) and when it's left, it becomes invisible ( opacity 0.0 ). It works fine, whenever I redraw the whole Layer of the specified shape.
The point is, I can't redraw the whole Layer because it takes to much time ( ~300 shapes ). For that reason I changed some code, to just draw the shape.
jsFiddle:
http://jsfiddle.net/p39uH/2/ ( see lines 25 and 30 of HTML )
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var pentagon = new Kinetic.RegularPolygon({
x: stage.width()/2,
y: stage.height()/2,
sides: 5,
radius: 70,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
opacity: 0.1
});
pentagon.on('mouseover', function() {
this.opacity(0.3);
this.draw(); // instead of layer.draw();
});
pentagon.on('mouseout', function() {
this.opacity(0.0);
this.draw(); // instead of layer.draw();
});
// add the shape to the layer
layer.add(pentagon);
// add the layer to the stage
stage.add(layer);
( Code is based on this: http://www.html5canvastutorials.com/kineticjs/html5-canvas-set-alpha-with-kineticjs/ )
Even though I set the opacity of the shape to 0.0 when left, it's still visible as you can see. Every time it is hovered, it becomes more and more visible ( I guess the shape gets redrawn ).
Is there any way to (re)draw the shape with an opacity of 0.0 WITHOUT drawing the whole stage and/or layer ?
Thanks in advance.
Yes, a quick look indicates node.draw() might be broken in 5.0.1.
Workarounds:
Drop back to version 4.4.0
Use layer.drawScene() which saves redraw time by not redrawing the hit-canvas.

Categories

Resources