I would like to do a path fading effect that would make the path disappear by fading its stroke progressively along the path.
What I'm able to do for now is removing one by one each of the segments of the path, producing a rather poor effect: sketch.
var circle = new Path.Circle({
center: view.center,
radius: 50,
strokeColor: 'black',
closed: false
});
circle.addSegment(circle.firstSegment);
fade();
function fade() {
if (circle.segments.length > 0) {
setTimeout(function() {
circle.lastSegment.remove();
fade();
}, 1000);
}
}
Is there a way to make the animation smoother ?
To do a smooth path animation, you don't have to necessarily remove segments, you can also play with path.dashArray and path.dashOffset.
By setting dash array to the length of the path and by animating dash offset, you can achieve what you are looking for.
Look at this schema for better understanding:
Here is a sketch demonstrating the solution.
// create path
var path = new Path.Circle({
center: view.center,
radius: 50,
strokeColor: 'black',
closed: false
});
path.addSegment(path.firstSegment);
// set dash array as long as path length
path.dashArray = [path.length, path.length];
// on frame...
function onFrame(event) {
// ...increment dash offset
path.dashOffset += 1;
}
Related
I have to display multiple features on the map using OpenLayers. Each feature must be represented by 2 images (2 SVG icons). One of this icons must be anchored at the features coordinates but the second must be shifted with a fixed amount of pixels. The additional problem is that shifted one must be also rotated and the center of rotation must be the center of icon and not a center of feature.
As an example I can say: there is an Icon of vehicle that is always oriented to the nord and there is another which shows direction that is rotated. The direction one must be always shown at the top of vehicle
I've tried to use various offsets and anchors but I was not able to precisely position the second icon
The code is done with ExtJS but I hope is readable:
So I'm using function fot set a style for a ImageVector:
me.imageVectorSource = new ol.source.ImageVector({
source: new ol.source.Vector({
features: me.features
}),
style: Ext.bind(me.pointStyleFunction,me)
});
And the function looks like:
pointStyleFunction: function(feature, resolution) {
var currentStyles =
[
new ol.style.Style({
//first icon
image: new ol.style.Icon({
src: 'resources/img/vehicle.test.svg',
scale: sc,
}),
//text shown below
text: new ol.style.Text({
text: textToShow,
scale:sc
fill: new ol.style.Fill({
color: 'yellow'
}),
offsetY: textOffset,
stroke: new ol.style.Stroke({
color: 'black',
width: 4
}),
})
}),
//second icon that should be rotated
var rpIconStyle = new ol.style.Style({
image: new ol.style.Icon({
src: 'resources/img/rp.svg',
scale: sc,
rotation: rot
}),
});
];
}
Now if second icon is rotated it is rotated around the center of the feature and not at the center of itself. I thought about adding new geometry to the second style (Point) but in such case I cannot specify offset (in pixels) of the geometry from the original feature's center. I can only use coordinates but have no idea if it is possible to convert them to pixels. In fact the expected solution would be something like in case of text property of style where offsetX and offsetY can be specified.
Could you please suggest me some solution?
You could use anchor but you would need to know the size of the scaled image. Using a second geometry as you suggested is easy, resolution is the meters per pixel, just multiply it by the number of pixels you want to offset by.
if (feature.getGeometry().getType() == 'Point') {
var coordinate = feature.getGeometry().getCoordinates();
var rpIconStyle = new ol.style.Style({
geometry: new ol.geom.Point([coordinate[0] + 50*resolution, coordinate[1] + 50*resolution]),
image: new ol.style.Icon({
src: 'resources/img/rp.svg',
scale: sc,
rotation: rot
}),
});
}
is there any way to add a shape in KonvaJS which draws outside of it's boundries? Basically a "hole" in the layer, so that I can highlight a spot in the canvas by making everything around a circle darker (black with low opacity).
Any help is much appreciated!
Cheers
Edit:
Here is an image of what I mean (I'm not allowed to embed it yet):
https://i.imgur.com/gvTqgN0.jpg
I was hoping there might be something like this:
Konva.Circle({
x: 100,
y: 100,
radius: 50,
opacity: 0.3,
fill: 'black',
inverted: true
})
and this would then in turn "not draw" a circle, but everything around it would then take the given attributes. In this case it would all be darkend a bit besides the circle.
You can do this with a custom shape:
const shape = new Konva.Shape({
width: stage.width(),
height: stage.height(),
// what is color of background ?
fill: 'rgba(0,0,0,0.2)',
sceneFunc: (ctx, shape) => {
// draw background
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(shape.width(), 0);
ctx.lineTo(shape.width(), shape.height());
ctx.lineTo(0, shape.height());
ctx.lineTo(0, 0);
// now cut circle from the background
// we can do this by useing arc
const x = 200;
const y = 200;
const radius = 10;
// but it must be counter-clockwise
// so the last argument true is very important here
ctx.arc(200, 200, 100, 0, Math.PI * 2, true);
ctx.fillStrokeShape(shape);
},
// remove shape from hit graph, so it is not visible for events
listening: false
});
Demo: https://jsbin.com/tevejujafi/3/edit?html,js,output
I’d like to rebuild this animation http://imgur.com/l5Vhswe in paper.js.
I already tried SVG animations (http://codepen.io/magglomag/pen/jrVwzy) but despite from the fact that they’ll be deprecated soon I was not able to move the two points asynchronously.
What I have so far is the shape and I know that I can animate with the onFrame event handler. But I have no clue how to say that the point should animate between the coordinates [43,168.7] and [43,35.3].
http://codepen.io/magglomag/pen/yaVXrr
var firstSegment = new Segment({
point: [109,3.7]
});
var secondSegment = new Segment({
point: [43,168.7]
});
var thirdSegment = new Segment({
point: [109,202.2]
});
var path = new Path({
segments: [firstSegment, secondSegment, thirdSegment],
fillColor: '#2dfd9a',
closed: true
});
secondSegment.onFrame = function(event) {
this.point = [43,35.3]
}
The error you are making is that you are trying to bind an handler to segment.onFrame event.
But only item.onFrame and view.onFrame are available.
In PaperScript context, you can even use a global onframe named function as a convenient way to animate things.
Here is a simple example demonstrating how a path segment can be animated.
// create a triangle
var triangle = new Path.RegularPolygon({
center: view.center,
sides: 3,
radius: 50,
fillColor: 'orange'
});
// store initial first point position
var initialPoint = triangle.firstSegment.point.clone();
// on frame
function onFrame(event) {
// use sine function as a convenient way to demonstrate animation
var newPoint = initialPoint + Math.sin(event.count * 0.05) * 30;
// update first point
triangle.firstSegment.point = newPoint;
}
I'm trying to rotate an image along it's Y axis, with the origin set to center of the image. But, the rotate animation is resulting in flickering. I tried to do the same in famo.us tutorials and could see the same there as well. Following is the modified code in the tutorial.
The tutorial link: http://famo.us/university/famous-101/animating/2/
Visit this page and replace the code in it with the following one.
The change in brief is, I'm using ImageSurface instead of Surface and applied rotateY.
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var ImageSurface = require('famous/surfaces/ImageSurface');
var Transform = require('famous/core/Transform');
var StateModifier = require('famous/modifiers/StateModifier');
var mainContext = Engine.createContext();
var imgSurface = new ImageSurface({
content: 'http://www.wpclipart.com/recreation/games/card_deck/cards_symbols/playing_card_symbols.png',
size: [200, 200]
});
var surface = new Surface({
size: [100, 100],
properties: {
color: 'white',
textAlign: 'center',
backgroundColor: '#FA5C4F'
}
});
var stateModifier = new StateModifier({origin: [0.5, 0.5]});
mainContext.add(stateModifier).add(imgSurface);
// stateModifier.setTransform(
// Transform.translate(50, 10, 0),
// { duration : 1000, curve: 'easeInOut' }
// );
stateModifier.setTransform(
Transform.rotateY(-Math.PI/4),
{ duration : 5000, curve: 'easeInOut' }
);
Any help would be appreciated.
Do you mean the flickering of the lines at the left and right?
This has to do with how the browser/GPU applies the 3d perspective transform on the image, but has nothing to do with famo.us really.
The image that you are using has a size of 505 x 499 pixels. Try resizing it using a graphics program to 200x200 and see whether you get better results.
The problem is that the rotating element is too close to the background and intersects it. If you position the rotating surface far enough in the z axis, the flickering, surely disappear.
Try something like this:
mainContext.add(new Modifier({transform: Transform.translate(0,0,100)})).add(stateModifier).add(imgSurface);
P.D: Sorry for my bad English...
I have tried to find a solution on how to implement fixed score table to visible stage (canvas) area by using kineticjs library layers and stages. The basic idea is that shape layer can be scrolled and stage is wider than the visible browser area but the score table should be all the time fixed to certain position on the visible area like in many casual games.
What would be the best approach on creating this kind of fixed always visible shapes to stage/canvas? Is there a way to refer to visible area xy position?
Your best bet for making a fixed position group is either to use a second layer on the stage or to create two groups for your objects - one that remains in place and another that can be moved. I'd go with the dual-layer approach as this allows you to redraw the layers separately so that when one has updated information, you don't need to redraw the other.
cvsObj.page = new Kinetic.Layer();
cvsObj.dynamic = new Kinetic.Layer();
cvsObj.stage.add(cvsObj.page);
cvsObj.stage.add(cvsObj.dynamic);
I took the two layer approach but actually my challenge was how to implement 'page' static behavior. I figured out that as it seems that Kinetic layers/stages do not offer methods for this I need to use other means to make 'page' layer on top of viewable area. I used jquery scrollTop() and scrollLeft()functions for this. And layer method .setAbsolutePosition() is used to update position for whole layer. Here pageLayer position is updated and dynamicLayer not so naming might be bit confusing but reflects what you see on browser.
Here is a simple example what does what I was looking for. Now the green rectangle moves when you scroll stage and the red rectangle and the x/y position counter stay on visible area. I attach this solution here with tutorial type of content as it might be useful.
<script>
window.onload = function() {
var stage = new Kinetic.Stage({
container: 'container',
width: 1600, height: 1600
});
var layerDynamic = new Kinetic.Layer();
var layerPage = new Kinetic.Layer();
var rectGreen = new Kinetic.Rect({
x: 239, y: 75, width: 100, height: 50, fill: 'green'
});
var rectRed = new Kinetic.Rect({
x: 100, y: 75, width: 100, height: 50, fill: 'red'
});
var simpleText = new Kinetic.Text({
x: 1, y: 1, text: "Init", textFill: "black"
});
layerDynamic.add(rectGreen);
layerPage.add(rectRed);
layerPage.add(simpleText);
$(document).scroll(function(e) {
var visibleXTop = $(this).scrollTop();
var visibleYTop = $(this).scrollLeft();
simpleText.setAttrs({text: visibleXTop + ' ' + visibleYTop});
layerPage.setAbsolutePosition(visibleYTop , visibleXTop);
layerPage.draw();
});
stage.add(layerDynamic);
stage.add(layerPage);
};
</script>