Possiblity to dynamically and smoothly change the colors of the entities

410 views
Skip to first unread message

Oleg

unread,
Oct 16, 2017, 9:12:06 AM10/16/17
to cesium-dev
1. A concise explanation of the problem you're experiencing.
No possiblity to dynamically and smoothly change the colors of the entities. In the case that I use to illustrate the problem, a series of yellow circles is created, and it is required that the transparency of the circles should gradually change over time. It can be implemented by means of direct access to the material property of the ellipse entities, but this way doesn't work well since it interferes with the animation of other entities and due to it makes the circles blink. I tried to implement the updates via the CallbackProperty, but I didn't manage to find a solution. Could you please help to solve the problem?


2. A minimal code example. If you've found a bug, this helps us reproduce and repair it.

//------------------------------- START VIEWER ---------------------------------
var viewer = new Cesium.Viewer('cesiumContainer', {
  navigationHelpButton: false,
  animation: false,
  timeline: false,
  homeButton: false,
  scene3DOnly : true
});

//----------------------------- NAVIGATE TO PLACE ------------------------------
var lon = 40, lat = 60;
viewer.camera.flyTo({destination: Cesium.Cartesian3.fromDegrees(lon, lat, 1000), duration: 1});

//--------------------- MANAGE THE ARRAY OF YELLOW CIRCLES ---------------------
var yellowCircles = {}; // Define the array of yellow circles

// Another yellow circle appears in a random place every 5 seconds.
// The lifetime of each circle is 30 seconds
setInterval(function(){
  var yc = new createYellowCircle(); // Create a new circle
  yellowCircles[yc.id] = yc; // Copy the circle to the array
}, 5000);

// This procedure inspects all circles 4 times per second
// to change the alphas in their material parameters and to remove expired circles
setInterval(function(){
  for(var c in yellowCircles){ // Look through all yellow circles
    var c_entity = viewer.entities.getById(c); // Get an entity of yellow circle
    var now = new Date().getTime() / 1000;
    var expiration = (now - yellowCircles[c].created) / yellowCircles[c].lifetime; // Check if the circle lifetime is expired or not
    if(expiration < 1){ // If the circle is not expired
      var alpha = 1 - expiration; // Calculate new alpha (it should decrease from 1 to 0 over time)
      yellowCircles[c].color = Cesium.Color.YELLOW.withAlpha(alpha); // Use alpha to update property color of the yellow circle object
      /* The commented below operation allows to update the colors, but this solution doesn't work well, since
          1) it eventually starts oppressing the animation of other objects,
          2) it makes circles blinking
      */
      /*
      c_entity.ellipse.material = new Cesium.ColorMaterialProperty(yellowCircles[c].color);
      */
    } else{ // If the circle is expired
      viewer.entities.remove(c_entity); // Remove entity frome viewer
      delete yellowCircles[c]; // Remove the correspondent object instance from the array of yellow circles
    }
  }
}, 250);

// This is an object constructor that creates a new yellow circle
createYellowCircle = function(){
  this.created = new Date().getTime() / 1000; // In seconds
  this.lifetime = 30; // In seconds
  this.color = Cesium.Color.YELLOW.withAlpha(1); // Start from alpha = 1 (opaque circle)
  var longitude = lon + 200 * (Math.random() - 0.5) * 1e-5; // Generate the coordinates randomly
  var latitude = lat + 200 * (Math.random() - 0.5) * 1e-5;
  this.id = Math.floor(Math.random() * 1e12).toString(); // Generate the unique id of the entity
  this.entity = {
    id : this.id,
    position : Cesium.Cartesian3.fromDegrees(longitude, latitude),
    /*
      The parameter upadate by means of CallbackProperty works fine for position updates,
      but it neither allows to update entire ellipse nor
      separately its material property
    */
    /*
    ellipse : new Cesium.CallbackProperty(function(){
      return {
        semiMinorAxis : 25,
        semiMajorAxis : 25,
        material : new Cesium.ColorMaterialProperty(this.color)
      };
    }, false)
    */
    ellipse : {
      semiMinorAxis : 25,
      semiMajorAxis : 25,
      material : new Cesium.ColorMaterialProperty(this.color) // !!! No possibility to dynamically update alpha
    }
  };
  viewer.entities.add(this.entity);
  viewer.camera.flyTo({destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, 500), duration: 2.5}); // Find the new circle on the map
};



3. Context. Why do you need to do this? We might know a better way to accomplish your goal.
Object color updates are commonly used in graphical applications.


4. The Cesium version you're using, your operating system and browser.
Cesium 1.38, Windows, Chrome


Oleg

unread,
Oct 17, 2017, 6:26:07 AM10/17/17
to cesium-dev
I found the hint at the sandcastle reference https://cesiumjs.org/Cesium/Apps/Sandcastle/?src=Hello%20World.html&label=Showcases&gist=635b076158394095e4a4cfa7b0cb78a6
Br, Oleg

понедельник, 16 октября 2017 г., 16:12:06 UTC+3 пользователь Oleg написал:

Oleg

unread,
Oct 17, 2017, 9:18:58 AM10/17/17
to cesium-dev
// I eventually found that the code below solves the problem

//------------------------------- START VIEWER ---------------------------------
var viewer = new Cesium.Viewer('cesiumContainer');

var lon = 109.17, lat = 55.2;

viewer.camera.flyTo({destination: Cesium.Cartesian3.fromDegrees(lon, lat, 1000), duration: 1});

//--------------------- MANAGE THE ARRAY OF YELLOW CIRCLES ---------------------
var yellowCircles = {}; // Define the array of yellow circles

// Another yellow circle appears in a random place every 5 seconds
setInterval(function(){
  var circleID = Math.floor(Math.random() * 1e12).toString(); // Generate the unique id of the circle object and its entity
  yellowCircles[circleID] = new createYellowCircle(circleID); // Create a new circle
}, 5000);

// The procedure to inspect all circles 4 times per second to change the alphas in their color material parameters and to remove the expired circles
setInterval(function(){
  for(var c in yellowCircles){ // Look through all yellow circles
    if(yellowCircles[c].isExpired()){
      var c_entity = viewer.entities.getById(c); // Get the yellow circle entity
      viewer.entities.remove(c_entity); // Remove entity from the viewer
      delete yellowCircles[c]; // Remove the correspondent object instance from the array of yellow circles
    }
  }
}, 250);

// An object constructor that creates a new yellow circle
function createYellowCircle(circleID){
  var created = new Date().getTime() / 1000; // Time of circle creation, in seconds
  var lifetime = 30; // // The lifetime of each circle is 30 seconds
  var expired = false;
  this.isExpired = function(){
    return expired;
  }
  var color = new Cesium.CallbackProperty(function(){ // Change color transparency dynamically
    var now = new Date().getTime() / 1000;
    var expiration = (now - created) / lifetime; // Check if the circle lifetime is expired or not
    if(expiration < 1) // If the circle is not expired
      var alpha = 1 - expiration;
    else {
      var alpha = 0;
      expired = true;
    }
    return Cesium.Color.YELLOW.withAlpha(alpha);
  }, false);
  var longitude = lon + 200 * (Math.random() - 0.5) * 1e-5; // Generate the coordinates randomly
  var latitude = lat + 200 * (Math.random() - 0.5) * 1e-5;
  var entity = {
    id : circleID,
    position : Cesium.Cartesian3.fromDegrees(longitude, latitude),
    ellipse : {
      semiMinorAxis : 25,
      semiMajorAxis : 25,
      material : new Cesium.ColorMaterialProperty(color)
    }
  };
  viewer.entities.add(entity);
  viewer.camera.flyTo({destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, 750), duration: 2}); // Find the new circle on the map
};

Gabby Getz

unread,
Oct 17, 2017, 10:57:48 AM10/17/17
to cesium-dev
Hi Oleg,

Very neat looking example, I'm glad you were able to figure this out! 😀

Just a suggestion- if you wanted this to scale and be more efficient, you could instantiate a list of entities up front. When you want to add another circle, just check to see if an entity is "expired" and just update that value rather than create a whole new entity.

Thanks!
Gabby

--
You received this message because you are subscribed to the Google Groups "cesium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cesium-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Oleg

unread,
Oct 18, 2017, 6:44:45 AM10/18/17
to cesium-dev
Thank you, Gabby!
I'll follow your suggestion.
Br, Oleg

вторник, 17 октября 2017 г., 17:57:48 UTC+3 пользователь Gabby Getz написал:
To unsubscribe from this group and stop receiving emails from it, send an email to cesium-dev+...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages