Implementing Dynamic Visual Effects for Cesium Entities using CallbackProperty

1. Creating a Pulsing Point Entity

The following example demonstrates how to make a point entity flash by oscillating the alpha channel of its color. We define a state variable to track the current opacity level and a directional flag to switch between fading in and out.

function createPulsingPoint() {
    let currentOpacity = 1.0;
    let isFadingOut = true;

    viewer.entities.add({
        name: "Pulsing Point Entity",
        position: Cesium.Cartesian3.fromDegrees(116.23, 39.56, 0),
        point: {
            pixelSize: 15,
            color: new Cesium.CallbackProperty(function() {
                // Adjust opacity incrementally
                if (isFadingOut) {
                    currentOpacity -= 0.04;
                    if (currentOpacity <= 0) {
                        isFadingOut = false;
                    }
                } else {
                    currentOpacity += 0.04;
                    if (currentOpacity >= 1) {
                        isFadingOut = true;
                    }
                }
                return Cesium.Color.CYAN.withAlpha(currentOpacity);
            }, false),
            outlineWidth: 0,
            outlineColor: Cesium.Color.TRANSPARENT
        }
    });
}

2. Flashing Ellipse (Area) Entity

To polygon or area-based entities like ellipses, we apply the same logic to the material property. By wrapping the color callback in a ColorMaterialProperty, we can control the transparency of the surface.

function createFlashingEllipse() {
    let alphaLevel = 1.0;
    let direction = -1; // -1 for fading, 1 for brightening

    viewer.entities.add({
        name: "Flashing Circular Zone",
        position: Cesium.Cartesian3.fromDegrees(116.20, 39.53, 0),
        ellipse: {
            semiMinorAxis: 2500.0,
            semiMajorAxis: 2500.0,
            material: new Cesium.ColorMaterialProperty(
                new Cesium.CallbackProperty(function() {
                    alphaLevel += 0.02 * direction;

                    // Reverse direction at boundaries
                    if (alphaLevel <= 0.1) {
                        direction = 1;
                    } else if (alphaLevel >= 1.0) {
                        direction = -1;
                    }

                    return Cesium.Color.RED.withAlpha(alphaLevel);
                }, false)
            )
        }
    });
}

3. Toggling Billboard Visibility

Bilbloard images can be made to "blink" by toggling their show property. Instead of fading transparency, we use a threshold value to switch the visibility state on and off rapidly.

function createBlinkingBillboard() {
    let fadeFactor = 1.0;
    let isDecreasing = true;

    viewer.entities.add({
        name: 'Warning Billboard',
        position: Cesium.Cartesian3.fromDegrees(116.20, 39.53),
        billboard: {
            image: 'warning_icon.png',
            width: 64,
            height: 64,
            // Toggle visibility based on the fade factor
            show: new Cesium.CallbackProperty(function() {
                if (isDecreasing) {
                    fadeFactor -= 0.05;
                    if (fadeFactor <= 0) {
                        isDecreasing = false;
                    }
                } else {
                    fadeFactor += 0.05;
                    if (fadeFactor >= 1) {
                        isDecreasing = true;
                    }
                }
                // Return true if factor is above 0.5, creating a strobe effect
                return fadeFactor > 0.5;
            }, false)
        }
    });
}

4. Advanced Breathing Effect (Radius and Color)

To create a "breathing" animation where the circle expands and fades simultaneous, we synchronize the semiMinorAxis, semiMajorAxis, and the material color. The radius increases while the opacity decreases.

const minR = 50;
const maxR = 150;
let currentRadius = minR;
let isExpanding = true;
const position = Cesium.Cartesian3.fromDegrees(120.191, 30.255, 100);

// Callback for dynamic radius
const getDynamicRadius = () => {
    return new Cesium.CallbackProperty(() => {
        const step = 1.0;
        if (isExpanding) {
            currentRadius += step;
            if (currentRadius >= maxR) isExpanding = false;
        } else {
            currentRadius -= step;
            if (currentRadius <= minR) isExpanding = true;
        }
        return currentRadius;
    }, false);
};

// Callback for dynamic color based on radius
const getDynamicColor = () => {
    return new Cesium.CallbackProperty(() => {
        // Calculate opacity inversely proportional to radius
        const opacity = 1 - (currentRadius - minR) / (maxR - minR);
        return new Cesium.Color(1, 0.5, 0, opacity);
    }, false);
};

viewer.entities.add({
    position: position,
    ellipse: {
        semiMinorAxis: getDynamicRadius(),
        semiMajorAxis: getDynamicRadius(),
        material: new Cesium.ColorMaterialProperty(getDynamicColor()),
        height: 0,
        outline: false
    }
});

5. Randomizing Colors for Polyline Volumes

You can also use CallbackProperty to generate random effects, such as changing the color of a geometry continuously on every frame.

function createRandomColorTube() {
    const shape = computeCircle(6000.0);
    
    viewer.entities.add({
        name: 'Random Color Tube',
        polylineVolume: {
            positions: Cesium.Cartesian3.fromDegreesArray([
                -85.0, 32.0,
                -85.0, 36.0,
                -89.0, 36.0
            ]),
            shape: shape,
            material: new Cesium.ColorMaterialProperty(
                new Cesium.CallbackProperty(function() {
                    return Cesium.Color.fromRandom({
                        minimumRed: 0.5,
                        minimumGreen: 0.5,
                        minimumBlue: 0.5,
                        alpha: 1.0
                    });
                }, false)
            )
        }
    });

    viewer.zoomTo(viewer.entities);
}

// Helper function to generate circle shape
function computeCircle(radius) {
    const positions = [];
    for (let i = 0; i < 360; i++) {
        const rad = Cesium.Math.toRadians(i);
        positions.push(new Cesium.Cartesian2(radius * Math.cos(rad), radius * Math.sin(rad)));
    }
    return positions;
}

Tags: cesium javascript geospatial callbackproperty visualization

Posted on Sun, 17 May 2026 05:24:12 +0000 by red-x