<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Transposed multidimensional ImageryTileLayer | Sample | ArcGIS Maps SDK for JavaScript</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.5.1"></script>
<!-- Load the ArcGIS Maps SDK for JavaScript from CDN -->
<script type="module" src="https://js.arcgis.com/5.1/"></script>
line-height: var(--calcite-font-line-height-fixed-base);
<arcgis-map basemap="dark-gray-vector" center="-85, 40" zoom="3">
<arcgis-zoom slot="top-left"></arcgis-zoom>
<arcgis-expand slot="top-left" expand-icon="legend" expand-tooltip="Legend">
<arcgis-legend></arcgis-legend>
<arcgis-expand expanded slot="bottom-left" expand-icon="clock">
<arcgis-time-slider id="timeSlider" mode="instant"></arcgis-time-slider>
heading="Wind Rose Chart"
description="Daily average wind direction and speed between 1/1/2011 - 12/31/2011"
<calcite-block expanded id="instructionsDiv" heading="Instructions">
Data displays daily average wind direction and speed as recorded on Jan 1, 2011.<br /><br />
Use the time slider to animate through time.<br /><br />
Click on the wind directions data on the map to see the general wind direction (blew-from) and speed (m/s) for
each day of 2011. <br />Learn more about
href="https://www.epa.gov/sites/default/files/2019-01/documents/how_to_read_a_wind_rose.pdf"
<canvas id="windRose-chart" height="300" width="300" hidden></canvas>
const ImageryTileLayer = await $arcgis.import("@arcgis/core/layers/ImageryTileLayer.js");
// create a new instance of an imagery tile layer and apply
// VectorFieldRenderer to show the speed and direction of wind
const layer = new ImageryTileLayer({
url: "https://tiledimageservices.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/NLDAS2011_daily_wind_magdir/ImageServer",
title: "2011 wind - 10 meters above surface",
style: "beaufort-m", // Beaufort point symbol (meters)
flowRepresentation: "flow-to",
field: "Magnitude", // values read from the first band
field: "Direction", // values read from the second band
rotationType: "geographic", // "arithmetic" is the default
const viewElement = document.querySelector("arcgis-map");
const timeSlider = document.querySelector("arcgis-time-slider");
const instructionsElement = document.getElementById("instructionsDiv");
const chartCanvas = document.getElementById("windRose-chart");
await viewElement.viewOnReady();
viewElement.map.add(layer);
await viewElement.whenLayerView(layer);
// get all the time dimension values from the service and create an array of dates
const windEpochDates = layer.serviceRasterInfo.multidimensionalInfo.variables[0].dimensions[0].values;
const windDates = windEpochDates.map((date) => new Date(date));
// time slider component initialization
// users can visualize daily wind information for all the time dimension available
timeSlider.fullTimeExtent = {
start: windDates[0], // Jan 1, 2011,
end: windDates[windDates.length - 1], // Dec 31, 2011
// set the stops to match the dates coming from time dimension
// Get wind direction and speed info for all the time dimension values available from this
// transposed multidimensional service - identify will return 365 values for the each day of 2011
viewElement.addEventListener("arcgisViewClick", async (event) => {
const mapPoint = event.detail.mapPoint;
await getWindSamples(mapPoint);
async function getWindSamples(currentLocation) {
if (!currentLocation || !layer.serviceRasterInfo.hasMultidimensionalTranspose) {
// set the transposedVariableName for the identify method. Identify method will return
// values for all the slices since multidimensionalDefinition is not defined
const results = await layer.identify(currentLocation, {
transposedVariableName: "wind_magdir",
if (!results.dataSeries) {
// first number is the magdirValue array is the wind magnitude
// second number is the magdirValue array is the direction the wind blew from.
const pixelValues = results.dataSeries.map(({ magdirValue }) => [magdirValue[0], magdirValue[1]]);
const data = getFrequencies(pixelValues);
chartCanvas.hidden = false;
instructionsElement.hidden = true;
// The layer is displaying the wind data in beaufort meters.
// Create wind rose chart based on the layer legend
// https://en.wikipedia.org/wiki/Beaufort_scale
// https://www.weather.gov/mfl/beaufort
const forces = [0.2, 1.8, 3.3, 5.4, 8.5, 11, 14.1, 17.2, 20.8, 24.4, 28.6, 32.7];
const forcesLabels = forces.map((force, index) => `${index === 0 ? 0 : forces[index - 1]}-${force}`);
const backgroundColor = [
"rgb(101,137,184)", //1.8
"rgb(132,158,186)", //3.3
"rgb(162,180,189)", //5.4
"rgb(192,204,190)", //8.5
"rgb(255,255,191)", //14.1
"rgb(255,220,161)", //17.2
"rgb(245,152,105)", //20.8
"rgb(237,117,81)", //24.4
"rgb(237,117,81)", //28.6
const directionLabels = [
const formatPercent = (value) => `${Math.round((value * 100) / daysInYear)}%`;
// this function calculates the percentage of different wind speeds (12 beaufort scales) flew
// from 16 different directions.
function getFrequencies(data) {
const segmentAngle = 360 / segments;
const windSpeedFrequency = Array.from({ length: segments }, () => new Float32Array(forces.length));
// get the beaufort scale meters per second
const getBeaufortScale = (windSpeed) => {
const scale = forces.findIndex((force) => force >= windSpeed);
return scale === -1 ? forces.length : scale;
// loop through wind data and set the beaufort wind scale
for (const [windSpeed, direction] of data) {
// check the given direction and identify which sector it belongs to the chart
const directionSegment = Math.min(Math.round((direction + segmentAngle / 2) / segmentAngle), segments - 1);
const windScale = getBeaufortScale(windSpeed);
if (windScale > 0 && windScale < forces.length) {
windSpeedFrequency[directionSegment][windScale]++;
// prep the wind rose chart data for the polarArea chart
return Array.from({ length: forces.length }, (_, index) =>
windSpeedFrequency.map((frequency) => frequency[index]),
function drawChart(data) {
const dataset = data.map((item, i) => ({
backgroundColor: backgroundColor[i],
const ctx = chartCanvas.getContext("2d");
windRoseChart = new Chart(ctx, {
label: (tooltipItem) => {
let label = tooltipItem.dataset.label || "";
label += formatPercent(tooltipItem.raw);
windRoseChart.data.datasets = dataset;