ThreeJS – smooth scaling object while mouseover - object

another ThreeJS question:
How can I make a hovered (intersected) object scale smooth to a defined size? My current code is
INTERSECTED.scale.x *= 1.5;
INTERSECTED.scale.y *= 1.5;
but this only works like on/off.
Edit: My Solution (with tweenJS)
While mouseOver I scale up the element to 200% :
function scaleUp(){
new TWEEN.Tween( INTERSECTED.scale ).to( {
x: 2,
y: 2
}, 350 ).easing( TWEEN.Easing.Bounce.EaseOut).start();
}
While mouseOut I scale down the element to 100% :
function scaleDown(){
new TWEEN.Tween( INTERSECTED.scale ).to( {
x: 1,
y: 1
}, 350 ).easing( TWEEN.Easing.Bounce.EaseOut).start();
}
Finally I call the functions in the mouse function.
if (intersects[0].object != INTERSECTED)
scaleUp();
else
scaleDown();
That's all. Very useful for UIs I think.

Using the tween library (found in three.js/examples/js/libs/tween.min.js) you can animate the scale like so:
function setupObjectScaleAnimation( object, source, target, duration, delay, easing )
{
var l_delay = ( delay !== undefined ) ? delay : 0;
var l_easing = ( easing !== undefined ) ? easing : TWEEN.Easing.Linear.None;
new TWEEN.Tween( source )
.to( target, duration )
.delay( l_delay )
.easing( l_easing )
.onUpdate( function() { object.scale.copy( source ); } )
.start();
}
and then call it like so:
setupObjectScaleAnimation( INTERSECTED,
{ x: 1, y: 1, z: 1 }, { x: 2, y: 2, z: 2 },
2000, 500, TWEEN.Easing.Linear.None );
Or if you want to use the render loop:
clock = new THREE.Clock();
time = clock.getElapsedTime();
INSPECTED.scale.x = time / 1000;
INSPECTED.scale.y = time / 1000;
You can change the divisor based on how fast or slow you want the animation to happen.

Related

How to make a sprite moving at the same speed of tileSprite in Phaser3

I am new in Phaser.
I want to make a background which represent the ground moving and there should be a bunch of rocks above it which I made them as a sprite group.
I made the ground as a tileSprite, and on each update I changed the tilePositionX. my problem is how to set the velocity of the rocks to match the update in the background so they appear to be on the ground and moving at the same speed of the ground.
theoretically you could measure the passed time, from the last update function call, and calculate the difference, or just eye-ball the needed velocity. (aka. try different velocities until it matches up with the background-movement):
Update:
If no physics object is needed you could move the "rock" "manually", this is very easy.
Here a quick demo, that I eye-balled:
The red mushroom, uses physics and velocity. Warning: the speed of the object can/will vary depending on the browser and hardware.
Update: The green mushroom, is moved manually via the position.
// Minor formating for stackoverflow
document.body.style = "display: flex;flex-direction: column;";
var config = {
type: Phaser.AUTO,
width: 536,
height: 150,
physics:{
default: 'arcade',
arcade: { debug: true }
},
scene: {
preload,
create,
update
}
};
var tilesprite;
var redRock;
var greenRock;
function preload ()
{
this.load.image('mushroom', 'https://labs.phaser.io/assets/sprites/mushroom16x16.png');
}
function create ()
{
tilesprite = this.add.tileSprite(400, 300, 800, 600, 'mushroom');
redRock = this.add.image(400, 40, 'mushroom').setScale(2);
redRock.setTint(0xff0000);
this.physics.add.existing(redRock);
redRock.body.setVelocityX(-60)
greenRock = this.add.image(400, 90, 'mushroom').setScale(2);
greenRock.setTint(0x00ff00);
}
function update (time, delta){
tilesprite.tilePositionX += 1;
let speedCorrection = (1000/60)/delta;
redRock.body.setVelocityX(-60 * speedCorrection )
greenRock.x -= 1;
// extra "reset" Rock
if( redRock.x + 16 < 0 ){
redRock.x = this.sys.game.canvas.width + 16;
greenRock.x = this.sys.game.canvas.width + 16;
}
}
var game = new Phaser.Game(config);
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js">
</script>
Disclaimer: It is not the most elegant solution, but it took me literally 30 Seconds to find a matching velocity.
Minor Update:
I improved the eye-ball-method with a speed correction, it can cause minor flickering/slipping(max 1-2 pixel skips), but should move constant on "all" device.
The change is just adding a small calculation let speedCorrection = (1000/60)/delta;

Is it possible to morph SVG's paths using Velocity.js?

Is it possible to morph SVG's paths using Velocity.js?
FROM
"M292,129c55.2,0,193,125.8,193,181S365.7,506,310.5,506S136,355.2,136,300S236.8,129,292,129z"
TO
"M230,38c55.2,0,348,57.8,348,113S391.2,569,336,569S55,456.2,55,401S174.8,38,230,38z"
var path = document.querySelectorAll('svg path');
Velocity(path[0], {
tween: 1000
}, {
duration: 6000,
easing: 'easeOutBounce',
progress: function (el, c, r, s, t) {
el[0].setAttribute('d', ??????);
}
});
EDIT: Please note I am the author of the code that enabled this in 2016, so it is the official supported way to do it!
Almost, should be something like this:
var path = document.querySelectorAll('svg path'),
from = "M292,129c55.2,0,193,125.8,193,181S365.7,506,310.5,506S136,355.2,136,300S236.8,129,292,129z",
to = "M230,38c55.2,0,348,57.8,348,113S391.2,569,336,569S55,456.2,55,401S174.8,38,230,38z";
Velocity(path[0], {
tween: [to, from]
}, {
duration: 6000,
easing: 'easeOutBounce',
progress: function(elements, complete, remaining, start, tweenValue) {
elements[0].setAttribute('d', tweenValue);
}
});
Edit: Velocity has some string animation support built in, see Rycochets answer below.
If not you could try doing that yourself, by breaking down the path string into an array.
One way could be to use the path data polyfill (as Chrome has deprecated that feature to give easy access to the array points) at polyfill. Then you could loop similar to below through the path points and interpolate.
You could also try using some regex to split and then build back up, a quick example could be something like the following. It's probably not complete (I haven't really tested the regex, and you may get varying number of elements if there are some characters that I haven't thought of).
$velocity=$("#mypath");
var fromPath = "M292,129c55.2,0,193,125.8,193,181S365.7,506,310.5,506S136,355.2,136,300S236.8,129,292,129z";
var toPath = "M230,38c55.2,0,348,57.8,348,113S391.2,569,336,569S55,456.2,55,401S174.8,38,230,38z";
var re = /(([+-]?[0-9\.]+)|[a-z]|\s+)([eE][-+]?[0-9]+)?/gi
var fromMatch = fromPath.match(re)
var toMatch = toPath.match(re)
$velocity.velocity(
{ opacity: 0.5, tween: [0,1] },
{ progress: function( el, complete, remaining, start, tweenValue) {
var interpPath = '';
for( c=0; c<fromMatch.length; c++) {
if( !isNaN( fromMatch[c]) ) {
interpPath += ( toMatch[c] - fromMatch[c] ) * tweenValue + +fromMatch[c]
} else {
interpPath += toMatch[c]
}
}
el[0].setAttribute('d', interpPath)
} }
)
jsfiddle

raphael change animation direction

simple by using rapheal i successfully make animation along path , but i can't reverse the animation direction ,,, just how to make it animate to the other direction when clicking the same path .
var paper = Raphael(0,0,1024,768);
var pathOne = paper.path(['M', 15,15 , 100,75]).attr({'stroke-width':18}).data("id",1);
//and this is just the circle
var circle = paper.circle(0, 0, 13).attr({
fill: '#09c', cursor: 'pointer'
});
//make the path as custom attribute so it can ba accessed
function pathPicker(thatPath){
paper.customAttributes.pathFactor = function(distance) {
var point = thatPath.getPointAtLength(distance * thatPath.getTotalLength());
var dx = point.x,
dy = point.y;
return {
transform: ['t', dx, dy]
};
}
}
//initialize for first move
pathPicker(pathOne);
circle.attr({pathFactor: 0}); // Reset
//Asign first path and first move
function firstMove(){
circle.animate({pathFactor: 1}, 1000});
}
pathOne.click(function(){
firstMove();
});
I couldn't get the original to run, so here is something using the main bits that should suit...
There's not a lot to it, get the length of the path, iterate over the length, draw object at the path. It uses the Raphael customAttributes to be able to animate it. I've added a custom toggle to make it easy to switch between them.
These are the key changes..
var len = pathOne.getTotalLength();
paper.customAttributes.along = function (v) {
var point = pathOne.getPointAtLength(v * len);
return {
transform: "t" + [point.x, point.y] + "r" + point.alpha
};
};
circle.attr({ along: 0 });
function animateThere( val ) {
val = +!val; // toggle
pathOne.click( function() { animateThere( val ) } );
circle.animate({ along: val }, 2000 );
};
pathOne.click( function() { animateThere(0) } );
jsfiddle
For completeness, you may want to do some extra checks like only allow the click if the animation has finished or something, as there may be a problem if you quickly click a lot and it buffering up animations.

NVD3 line chart with vertical line

I'm trying to generate a linechart in NVD3 with a vertical line. Particularly this kind of line chart.
The linechart has two panels a viewing panel and a zoom panel, I would want the line to be on both.
Something like this:
Is this feasible?
Edit:
I found out a way to do this by just appending to the data an extra stream which represents a line. e.g.
streams[3] = {key:'myline', values:[{x:68,y:0},{x:68,y:7}]}
Is there a better way?
Yes it's possible,
Here is an example of how to do it :
https://gist.github.com/timelyportfolio/80d85f78a5a975fa29d7#file-code-r
The solution here is to add a javascript function drawing vertical lines using NVD3 ( read carefully the comments ) :
function drawVerticalLines(opts) {
// CAREFUL HERE !!! the css pasth ".nvd3 .nv-focus .nv-linesWrap" depends on the type of chart you are using, lineChart would use only ".nvd3 .nv-linesWrap" ... !
if (!(d3.select('#' + opts.id + ' the css pasth ".nvd3 .nv-focus .nv" depends on the type of chart you are using, lineChart would use only -linesWrap').select('.vertical-lines')[0][0])) {
// Adds new g element with .vertical-lines class; use a css debugger to verify
d3.select('#' + opts.id + ' .nvd3 .nv-focus .nv-linesWrap').append('g')
.attr('class', 'vertical-lines')
}
vertLines = d3.select('#' + opts.id + ' .nvd3 .nv-focus .nv-linesWrap').select('.vertical-lines').selectAll('.vertical-line')
.data(
[{
'date': new Date('1967-11-30'),
'label': 'something to highlight 1967'
}, {
'date': new Date('2001-11-30'),
'label': 'something to highlight 2001'
}])
var vertG = vertLines.enter()
.append('g')
.attr('class', 'vertical-line')
vertG.append('svg:line')
vertG.append('text')
vertLines.exit().remove()
// CAREFUL 2 : chart.xAxis.scale() scale depends how you are defining your x Axis in nvd3 chart ... if your are using timestamps, (d.date / 60 / 60 / 24 / 1000) becomes (d.date)
vertLines.selectAll('line')
.attr('x1', function(d) {
return chart.xAxis.scale()(d.date / 60 / 60 / 24 / 1000)
})
.attr('x2', function(d) {
return chart.xAxis.scale()(d.date / 60 / 60 / 24 / 1000)
})
.attr('y1', chart.yAxis.scale().range()[0])
.attr('y2', chart.yAxis.scale().range()[1])
.style('stroke', 'red')
vertLines.selectAll('text')
.text(function(d) {
return d.label
})
.attr('dy', '1em')
//x placement ; change dy above for minor adjustments but mainly
// change the d.date/60/60/24/1000
//y placement ; change 2 to where you want vertical placement
//rotate -90 but feel free to change to what you would like
.attr('transform', function(d) {
return 'translate(' +
chart.xAxis.scale()(d.date / 60 / 60 / 24 / 1000) +
',' +
chart.yAxis.scale()(2) +
') rotate(-90)'
})
//also you can style however you would like
//here is an example changing the font size
.style('font-size', '80%')
}
And call this method in nv.addGraph Callback :
var sharedChart = null; // Shared reference on the chart
nv.addGraph(function() {
.....
sharedChart = chart;
return chart;
,
function() {
drawVerticalLines(opts, sharedChart);
}
);
With opts ... (obviously you don't really need it):
var opts${widgetID.replace('-', '0')} = {
"dom": "chart${widgetID}",
"width": 800,
"height": 400,
"x": "date",
"y": "value",
"group": "variable",
"type": "lineWithFocusChart",
"id": "chart${widgetID}"
};
Hope this helps, it took me quite a long time to find it and to make it work !

OpenCV MatchTemplate limited to roi

My question is related to the use of matchTemplate in OpenCV. I'm able to use the function to find a template within the whole image. It is possible to limit the "searching area" to a restricted region within the image, i.e. using the roi? I tried to set the roi before calling matchTemplate but that didn't have any effect.
So, do you know any way to limit the search of the template to a subregion of the image? That because I know that my target can be found only in this limited region.
Here is some line of code taken directly from the OpenCV samples:
void MatchingMethod( int, void* )
{
// Source image to display
Mat img_display;
img.copyTo( img_display );
// Create the result matrix
int result_cols = img.cols - templ.cols + 1;
int result_rows = img.rows - templ.rows + 1;
result.create( result_cols, result_rows, CV_32FC1 );
// Do the Matching and Normalize
img.adjustROI(100, 100, 500, 500);
matchTemplate( img, templ, result, match_method );
normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );
// Localizing the best match with minMaxLoc
double minVal; double maxVal; Point minLoc; Point maxLoc;
Point matchLoc;
minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better
if( match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )
{ matchLoc = minLoc; }
else
{ matchLoc = maxLoc; }
// Show me what you got
rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
imshow( image_window, img_display );
imshow( result_window, result );
}
sure !
Rect roi( x,y,w,h );
matchTemplate( img( roi ), templ, result, method );

Resources