AnimatedFlowRenderer with effects and blending

Explore in the sandboxView live

This sample shows how to use the AnimatedFlowRenderer with layer effects and blendModes to display ocean currents and sea surface temperature data.

How it works

Normally, the AnimatedFlowRenderer only displays its streamlines in one solid color. To create a multivariate visualization with the AnimatedFlowRenderer, you can use layer blending. In this application, we're blending together an ocean currents layer (visualized by the animated flow renderer - which gives us the streamlines) and a sea surface temperature layer (visualized by a RasterStretchRenderer - which gives us the color). When initializing the currents layer, we give it a destination-in blendMode so that the temperature layer only draws where it overlaps with the currents layer.

Use dark colors for code blocks
                                                                                                                                                  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
  <title>AnimatedFlowRenderer with effects and blending | Sample | ArcGIS API for JavaScript 4.22</title>

  <link rel="stylesheet" href="https://js.arcgis.com/4.22/esri/themes/dark/main.css" />
  <script src="https://js.arcgis.com/4.22/"></script>

  <style>
    html,
    body,
    #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
      background-color:#4c4c4c;
  </style>

  <script>
   require([
      "esri/Map",
      "esri/views/MapView",
      "esri/layers/ImageryTileLayer",
      "esri/layers/TileLayer",
      "esri/layers/GroupLayer",
      "esri/rest/support/MultipartColorRamp",
      "esri/rest/support/AlgorithmicColorRamp",
      "esri/Color",
      "esri/widgets/Legend",
      "esri/widgets/Fullscreen"
    ], function (
      Map,
    ) {
      // serves as a basemap layer
      const spilhausBasemap = new TileLayer({
        url: "https://tiles.arcgis.com/tiles/nGt4QxSblgDfeJn9/arcgis/rest/services/Spilhaus_Vibrant_Basemap/MapServer",
        effect: "saturate(10%) brightness(0.3)" // dim brightness to create darker style basemap
      const colorRamp = new MultipartColorRamp({
        colorRamps: [
          new AlgorithmicColorRamp({
            fromColor: new Color([20, 100, 150, 255]),
            toColor: new Color([70, 0, 150, 255])
          new AlgorithmicColorRamp({
            fromColor: new Color([70, 0, 150, 255]),
            toColor: new Color([170, 0, 120, 255])
          new AlgorithmicColorRamp({
            fromColor: new Color([170, 0, 120, 255]),
            toColor: new Color([230, 100, 60, 255])
          new AlgorithmicColorRamp({
            fromColor: new Color([230, 100, 60, 255]),
            toColor: new Color([255, 170, 0, 255])
          new AlgorithmicColorRamp({
            fromColor: new Color([255, 170, 0, 255]),
            toColor: new Color([255, 255, 0, 255])
      // sea surface temperature, visualized with raster stretch renderer
      const temperatureLayer = new ImageryTileLayer({
        url: "https://tiledimageservices.arcgis.com/jIL9msH9OI208GCb/arcgis/rest/services/HyCOM_Surface_Temperature___Spilhaus/ImageServer",
        renderer: {
          "computeGamma": false,
          "gamma": [1],
          "useGamma": false,
          "stretchType": "min-max",
          "type": "raster-stretch"
      // ocean currents, visualized with animated flow renderer
      const currentsLayer = new ImageryTileLayer({
        url: "https://tiledimageservices.arcgis.com/jIL9msH9OI208GCb/arcgis/rest/services/Spilhaus_UV_ocean_currents/ImageServer",
        renderer: {
          type: "animated-flow", // autocasts to AnimatedFlowRenderer
          density: 1,
          lineLength: 10, // max length of a streamline will be 10
          lineWidth: "2px"
        },
        blendMode: "destination-in", // temperature layer will only display on top of this layer
      });
      const groupLayer = new GroupLayer({
        effect: "bloom(2, 0.5px, 0.0)", // apply bloom effect to make the colors pop
        layers: [temperatureLayer, currentsLayer]
      const map = new Map({
        basemap: {
          baseLayers: [spilhausBasemap]
        layers: [groupLayer]
      const view = new MapView({
        container: "viewDiv",
        map: map,
        scale: 40000000,
        center: [-98, 39]
      // add legend for temperature layer
      const legend = new Legend({
        view: view,
        layerInfos: [{
          layer: temperatureLayer,
          title: "Sea surface temperature"
      view.ui.add(legend, "top-right");
      // add fullscreen widget
      fullscreen = new Fullscreen({
        view: view
      view.ui.add(fullscreen, "top-left");
    </script>
  </head>
  <body>
    <div id="viewDiv"></div>
  </body>
</html>

Then, we add both layers to a GroupLayer. We apply the bloom layer effect to the group layer to make the colors glow on the dark basemap.

Use dark colors for code blocks
                                                                                                                                                  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
  <title>AnimatedFlowRenderer with effects and blending | Sample | ArcGIS API for JavaScript 4.22</title>

  <link rel="stylesheet" href="https://js.arcgis.com/4.22/esri/themes/dark/main.css" />
  <script src="https://js.arcgis.com/4.22/"></script>

  <style>
    html,
    body,
    #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
      background-color:#4c4c4c;
  </style>

  <script>
   require([
      "esri/Map",
      "esri/views/MapView",
      "esri/layers/ImageryTileLayer",
      "esri/layers/TileLayer",
      "esri/layers/GroupLayer",
      "esri/rest/support/MultipartColorRamp",
      "esri/rest/support/AlgorithmicColorRamp",
      "esri/Color",
      "esri/widgets/Legend",
      "esri/widgets/Fullscreen"
    ], function (
      Map,
    ) {
      // serves as a basemap layer
      const spilhausBasemap = new TileLayer({
        url: "https://tiles.arcgis.com/tiles/nGt4QxSblgDfeJn9/arcgis/rest/services/Spilhaus_Vibrant_Basemap/MapServer",
        effect: "saturate(10%) brightness(0.3)" // dim brightness to create darker style basemap
      const colorRamp = new MultipartColorRamp({
        colorRamps: [
          new AlgorithmicColorRamp({
            fromColor: new Color([20, 100, 150, 255]),
            toColor: new Color([70, 0, 150, 255])
          new AlgorithmicColorRamp({
            fromColor: new Color([70, 0, 150, 255]),
            toColor: new Color([170, 0, 120, 255])
          new AlgorithmicColorRamp({
            fromColor: new Color([170, 0, 120, 255]),
            toColor: new Color([230, 100, 60, 255])
          new AlgorithmicColorRamp({
            fromColor: new Color([230, 100, 60, 255]),
            toColor: new Color([255, 170, 0, 255])
          new AlgorithmicColorRamp({
            fromColor: new Color([255, 170, 0, 255]),
            toColor: new Color([255, 255, 0, 255])
      // sea surface temperature, visualized with raster stretch renderer
      const temperatureLayer = new ImageryTileLayer({
        url: "https://tiledimageservices.arcgis.com/jIL9msH9OI208GCb/arcgis/rest/services/HyCOM_Surface_Temperature___Spilhaus/ImageServer",
        renderer: {
          "computeGamma": false,
          "gamma": [1],
          "useGamma": false,
          "stretchType": "min-max",
          "type": "raster-stretch"
      // ocean currents, visualized with animated flow renderer
      const currentsLayer = new ImageryTileLayer({
        url: "https://tiledimageservices.arcgis.com/jIL9msH9OI208GCb/arcgis/rest/services/Spilhaus_UV_ocean_currents/ImageServer",
        renderer: {
          type: "animated-flow", // autocasts to AnimatedFlowRenderer
          density: 1,
          lineLength: 10, // max length of a streamline will be 10
          lineWidth: "2px"
        blendMode: "destination-in", // temperature layer will only display on top of this layer
      const groupLayer = new GroupLayer({
        effect: "bloom(2, 0.5px, 0.0)", // apply bloom effect to make the colors pop
        layers: [temperatureLayer, currentsLayer]
      });

      const map = new Map({
        basemap: {
          baseLayers: [spilhausBasemap]
        layers: [groupLayer]
      const view = new MapView({
        container: "viewDiv",
        map: map,
        scale: 40000000,
        center: [-98, 39]
      // add legend for temperature layer
      const legend = new Legend({
        view: view,
        layerInfos: [{
          layer: temperatureLayer,
          title: "Sea surface temperature"
      view.ui.add(legend, "top-right");
      // add fullscreen widget
      fullscreen = new Fullscreen({
        view: view
      view.ui.add(fullscreen, "top-left");
    </script>
  </head>
  <body>
    <div id="viewDiv"></div>
  </body>
</html>

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.