Cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Change animate duration

I am wondering if it is possible to change the duration of an animation depending on heart rate. I have tried changing it using heartImage.animate.dur, but I get this error  "Cannot set property 'dur' of undefined"

 

 

let heartImage = document.getElementById("heartImage");

myHeartRate.text = hrm.heartRate;
var beats = String(60/hrm.hearRate);
heartImage.animate.dur = beats;

 

 

<image id="heartImage" href="Heart.png" x="0" y="-1" width="100%" height="100%" class="foreground">
<animate attributeName="opacity" begin="load;activate" from="1" to="0" dur="1" final="restore" repeatCount="indefinite"/></image>

 

Best Answer
0 Votes
7 REPLIES 7

I don't think it's possible in the current firmware, but it might be possible in a future update.

 

You could try:

 

 

<image id="heartImage" href="Heart.png" x="0" y="-1" width="100%" height="100%" class="foreground">
<animate id="anim" attributeName="opacity" begin="load;activate" from="1" to="0" dur="1" final="restore" repeatCount="indefinite"/></image>
let heartImage = document.getElementById("heartImage");
let anim = heartImage.getElementById("anim");
anim.dur = beats;

Or just animate yourself using Javascript.

heartImage.style.fillOpacity = 0.5;

 

Best Answer

Hello there,

 

I wanted to achieve the same thing, but since the duration cannot (yet) be set in Code, I decided to go for a solution whereby I control the timing of the animation's starting point.

<image id="heartImage" href="Heart.png" x="0" y="-1" width="100%" height="100%" class="foreground">
    <animate id="anim" attributeName="opacity" begin="enable" from="1" to="0.5" dur="1" final="restore" repeatCount="1"/>
</image>

The Animation lasts 1 second and goes from opacity "1" to "0.5". But rather than continuously animate, I calculate the time when the animation starts (continuously). The animation starts at "enable". In Code, I make a function that executes the animation manually.

 

What it does do: pulse according to the heart-rate, since I restart the animation according to a timeout that is calculated using the heart-rate (1000ms * (60 / heart-rate)).

 

What it doesn't do: I cannot Control the Duration, wich is set to 1 second. So if the heart-rate is twice as fast (120), the animation will not actually get down to 0.5 opacity, but rather to 0.75.

Declarations/Imports:

 

import document from "document";
import { HeartRateSensor } from "heart-rate";
import { display } from "display";

let previousHeartRate = -1; // Remember the previous heart rate
let heartImage = document.getElementById("heartImage"); // Gets the Image element
let cancelAnimation = false; // To stop animating on Display off

Configure and start the HeartRateSensor:

// Start the heart rate monitor
let hrm = new HeartRateSensor();
hrm.onreading = function() {
let heartRate = hrm.heartRate;
  updateHeartRate(heartRate);
}
hrm.start();

Cancel the animation when the display switches off, and start it again when it switches on:

// Add display listener that cancels the continuous animation 
display.onchange = function() {
if (display.on) {
    cancelAnimation = false;
    animate();
  }
  else {
// Stop the current animation
    cancelAnimation = true;
  }
}

When the heart-rate is updated, this function is executed:

function updateHeartRate(heartRate) {  
  if (heartRate != previousHeartRate) {
cancelAnimation = true; // Stop the current Animation cycle
if (heartRate > 0) {
    previousHeartRate = heartRate;
}
else {
previousHeartRate = -1;
}
   
    if (display.on) {
      cancelAnimation = false;
      animate(); // Start animating
    }
  }
}

Here's the function that does the animation:

function animate() {
  if (display.on) {
    heartImage.animate("enable"); // Execute the animation

// Calculate the timeout (1000 is 1 second) let timeout = 1000 * (60 / previousHeartRate); if ( timeout < 0 ) { // In case the previousHeartRate is invalid timeout = 1000; }
// Only continue the animation if it has not been cancelled if (!cancelAnimation) {
// Animate after <timeout> in milliseconds (e.g. 120 = 1000 * (60 /120) = 500) setTimeout(function() {
// Execute the animation animate(); }, timeout); } }
}

so, the "cancelAnimation" variable allows me to Switch off the current Animation, since it animates continuously other wise. I only animate when the Display is on and I calculate the next execution time of the Animation using the heart rate.

 

I hope this helps, I've tried to make it easy to understand, but also build in some "safeguards" that Keep the animation from going on indefinately.

 

Regards,

JDT

 

Best Answer
0 Votes

While you still cannot change the "dur" attribute for the animation, you can change the "to" attribute.  Interestingly, if you use negative numbers for the "to" attribute, then the animation will speed up. Setting the "to" attribute to -1 sped the animation up by two. So I mapped the BPM to a negative number with the base BPM as 60.   

 

animate.to = map_number(bpm,60,120,0,-1);


function map_number(x,in_min,in_max, out_min, out_max){
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;

 

Note: I am changing the animate.to within the setInterval function call because that is how I am getting the function repeatedly call. 
}

Best Answer
0 Votes

I'm looking for a way to do similar myself.  

 

Easiest way I could get an animation going the way I want was to make a small PNG of a ECG in the lower right of my screen and then cover it with a rectangle.  I have a black background and the rectangle is black.  I move the rectangle to the right (off the screen) and it looks like an active ECG.  I would love to make it move faster depending on the heartbeat.

If this still isn't possible, I'm still happy with my animation effect.

Best Answer
0 Votes

@saaasaab wrote:

While you still cannot change the "dur" attribute for the animation,...


I'm not sure which firmware update fixed the dur visibility, but you can absolutely set the dur value now.

 

Like other GUI attributes, although it is initialized in the gui as a string, it is set in JavaScript as a number.

Best Answer
0 Votes

Actually your reply made me look closer at JonFitbit's answer.  

 

This does work if you implement it correctly.  But basically setting the id in the animation then calculating and setting the duration as anim.dur works great.  anim.dur = (90.00/hrm.heartRate); works for my animation.

 

If anyone else needs something similar:

 

index.js

 

let anim = document.getElementById("heartrateAnim");

// When the value changes, update text
hrm.onreading = function() {
// Peek the current sensor values
hrtValue.text = hrm.heartRate || 0;
// Set animation duration
anim.dur = (90.00/hrm.heartRate);
// Stop monitoring the sensor
hrm.stop();
}

 

 

index.gui

 

  <image href="heart.png" x="242" y="6" width="20" height="20" />
  <image href="heart.png" x="240" y="4" width="24" height="24" >
    <animate id="heartrateAnim" attributeName="opacity" from="0" to="1" dur="1" final="restore" repeatCount="indefinite" />
  </image>

 

Best Answer
0 Votes

What SDK are you using? I'm trying this on SDK 4.2 since I have a Versa 2 but is not working.

Best Answer
0 Votes