@amcharts/amcharts5-mcp 1.1.7 → 1.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/content/map.md +540 -101
- package/package.json +1 -1
package/content/map.md
CHANGED
|
@@ -1074,220 +1074,659 @@ Demonstrates: orthographic projection, single-segment lines for per-segment anim
|
|
|
1074
1074
|
</html>
|
|
1075
1075
|
```
|
|
1076
1076
|
|
|
1077
|
-
## Example 5: Map Sankey —
|
|
1077
|
+
## Example 5: Map Sankey — Global Coffee Supply Chain (sourceId/targetId)
|
|
1078
1078
|
|
|
1079
|
-
Demonstrates: `MapSankeySeries` with
|
|
1079
|
+
Demonstrates: `MapSankeySeries` with `sourceId`/`targetId` data (country codes), multi-level flows (producers > hubs > consumers), custom theme, country highlighting, animated coffee bean bullets, Globe/Map projection toggle, and auto-rotation. Based on the `map-sankey` shared example.
|
|
1080
1080
|
|
|
1081
1081
|
```html
|
|
1082
1082
|
<!DOCTYPE html>
|
|
1083
1083
|
<html>
|
|
1084
1084
|
<head>
|
|
1085
1085
|
<meta charset="UTF-8">
|
|
1086
|
-
<title>Map Sankey —
|
|
1086
|
+
<title>Map Sankey — Global Coffee Supply Chain</title>
|
|
1087
1087
|
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
|
|
1088
1088
|
<script src="https://cdn.amcharts.com/lib/5/map.js"></script>
|
|
1089
1089
|
<script src="https://cdn.amcharts.com/lib/5/geodata/worldLow.js"></script>
|
|
1090
1090
|
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
|
|
1091
|
-
<style
|
|
1091
|
+
<style>body { margin: 0; background: #f0e6d6; } #chartdiv { width: 100%; height: 600px; }</style>
|
|
1092
1092
|
</head>
|
|
1093
1093
|
<body>
|
|
1094
1094
|
<div id="chartdiv"></div>
|
|
1095
1095
|
<script>
|
|
1096
1096
|
var root = am5.Root.new("chartdiv");
|
|
1097
|
-
|
|
1097
|
+
|
|
1098
|
+
// Coffee theme — warm earth tones
|
|
1099
|
+
var coffeeTheme = am5.Theme.new(root);
|
|
1100
|
+
coffeeTheme.rule("InterfaceColors").setAll({
|
|
1101
|
+
primaryButton: am5.color(0x8b5e3c),
|
|
1102
|
+
primaryButtonHover: am5.color(0x5c3a1e),
|
|
1103
|
+
primaryButtonDown: am5.color(0x3c1e0e),
|
|
1104
|
+
primaryButtonActive: am5.color(0xc4956a),
|
|
1105
|
+
primaryButtonText: am5.color(0xf5ece0),
|
|
1106
|
+
secondaryButton: am5.color(0xe8d5b7),
|
|
1107
|
+
secondaryButtonHover: am5.color(0xd4c4a8),
|
|
1108
|
+
secondaryButtonDown: am5.color(0xc4956a),
|
|
1109
|
+
secondaryButtonText: am5.color(0x3c1e0e),
|
|
1110
|
+
background: am5.color(0xe8d5b7),
|
|
1111
|
+
text: am5.color(0x3c1e0e)
|
|
1112
|
+
});
|
|
1113
|
+
root.setThemes([am5themes_Animated.new(root), coffeeTheme]);
|
|
1114
|
+
|
|
1115
|
+
// Grainy paper background
|
|
1116
|
+
root.container.set("background", am5.Rectangle.new(root, {
|
|
1117
|
+
fill: am5.color(0xf0e6d6),
|
|
1118
|
+
fillPattern: am5.GrainPattern.new(root, {
|
|
1119
|
+
density: 0.4,
|
|
1120
|
+
maxOpacity: 0.07,
|
|
1121
|
+
colors: [am5.color(0x000000)]
|
|
1122
|
+
})
|
|
1123
|
+
}));
|
|
1124
|
+
|
|
1125
|
+
// Coffee palette
|
|
1126
|
+
var espresso = am5.color(0x3c1e0e);
|
|
1127
|
+
var darkRoast = am5.color(0x5c3a1e);
|
|
1128
|
+
var mediumRoast = am5.color(0x8b5e3c);
|
|
1129
|
+
var lightRoast = am5.color(0xc4956a);
|
|
1130
|
+
var crema = am5.color(0xe8d5b7);
|
|
1131
|
+
var cream = am5.color(0xf5ece0);
|
|
1098
1132
|
|
|
1099
1133
|
var chart = root.container.children.push(am5map.MapChart.new(root, {
|
|
1100
1134
|
panX: "rotateX",
|
|
1101
|
-
panY: "
|
|
1102
|
-
projection: am5map.
|
|
1135
|
+
panY: "rotateY",
|
|
1136
|
+
projection: am5map.geoOrthographic(),
|
|
1137
|
+
rotationX: -15,
|
|
1138
|
+
rotationY: -20,
|
|
1139
|
+
minZoomLevel: 0.5,
|
|
1140
|
+
zoomLevel: 0.9
|
|
1103
1141
|
}));
|
|
1104
1142
|
|
|
1105
|
-
//
|
|
1143
|
+
// Ocean / globe background
|
|
1144
|
+
var bgSeries = chart.series.push(am5map.MapPolygonSeries.new(root, {}));
|
|
1145
|
+
bgSeries.mapPolygons.template.setAll({
|
|
1146
|
+
fill: am5.color(0xede4d4), fillOpacity: 1, strokeOpacity: 0
|
|
1147
|
+
});
|
|
1148
|
+
bgSeries.data.push({ geometry: am5map.getGeoRectangle(90, 180, -90, -180) });
|
|
1149
|
+
|
|
1150
|
+
// Graticule
|
|
1151
|
+
var graticuleSeries = chart.series.push(am5map.GraticuleSeries.new(root, {}));
|
|
1152
|
+
graticuleSeries.mapLines.template.setAll({
|
|
1153
|
+
stroke: mediumRoast, strokeOpacity: 0.15, strokeWidth: 0.5
|
|
1154
|
+
});
|
|
1155
|
+
|
|
1156
|
+
// Countries
|
|
1106
1157
|
var polygonSeries = chart.series.push(am5map.MapPolygonSeries.new(root, {
|
|
1107
1158
|
geoJSON: am5geodata_worldLow
|
|
1108
1159
|
}));
|
|
1109
1160
|
polygonSeries.mapPolygons.template.setAll({
|
|
1110
|
-
fill:
|
|
1111
|
-
stroke: am5.color(0xffffff),
|
|
1112
|
-
strokeWidth: 0.5
|
|
1161
|
+
fill: cream, stroke: lightRoast, strokeWidth: 0.5, strokeOpacity: 0.5
|
|
1113
1162
|
});
|
|
1114
1163
|
|
|
1115
|
-
//
|
|
1164
|
+
// Highlight producer, hub, and consumer countries
|
|
1165
|
+
var producerIds = ["BR", "VN", "CO", "ET", "ID", "HN"];
|
|
1166
|
+
var hubIds = ["DE", "BE", "IT", "US"];
|
|
1167
|
+
var consumerIds = ["FR", "PL", "SE", "RU", "GB", "NL", "GR", "AT", "CA", "JP"];
|
|
1168
|
+
|
|
1169
|
+
polygonSeries.events.on("datavalidated", function() {
|
|
1170
|
+
am5.array.each(polygonSeries.dataItems, function(di) {
|
|
1171
|
+
var id = di.get("id");
|
|
1172
|
+
if (id && producerIds.indexOf(id) !== -1) {
|
|
1173
|
+
di.get("mapPolygon").setAll({ fill: am5.color(0x8fae7e) });
|
|
1174
|
+
} else if (id && hubIds.indexOf(id) !== -1) {
|
|
1175
|
+
di.get("mapPolygon").setAll({ fill: am5.color(0xc4a878) });
|
|
1176
|
+
} else if (id && consumerIds.indexOf(id) !== -1) {
|
|
1177
|
+
di.get("mapPolygon").setAll({ fill: am5.color(0xddc8a0) });
|
|
1178
|
+
}
|
|
1179
|
+
});
|
|
1180
|
+
});
|
|
1181
|
+
|
|
1182
|
+
// MapSankeySeries — coffee supply chain
|
|
1116
1183
|
var sankeySeries = chart.series.push(am5map.MapSankeySeries.new(root, {
|
|
1117
1184
|
polygonSeries: polygonSeries,
|
|
1118
|
-
maxWidth:
|
|
1185
|
+
maxWidth: 2,
|
|
1119
1186
|
controlPointDistance: 0.4,
|
|
1120
|
-
|
|
1187
|
+
resolution: 60,
|
|
1188
|
+
nodePadding: 0.3
|
|
1121
1189
|
}));
|
|
1122
1190
|
|
|
1123
|
-
// Band appearance
|
|
1124
1191
|
sankeySeries.mapPolygons.template.setAll({
|
|
1125
|
-
fill:
|
|
1126
|
-
fillOpacity: 0.
|
|
1192
|
+
fill: mediumRoast,
|
|
1193
|
+
fillOpacity: 0.65,
|
|
1127
1194
|
strokeOpacity: 0,
|
|
1128
|
-
tooltipText: "{
|
|
1195
|
+
tooltipText: "{sourceNode.name} > {targetNode.name}\n{value}k tonnes"
|
|
1129
1196
|
});
|
|
1130
1197
|
|
|
1131
|
-
// Node appearance
|
|
1132
1198
|
sankeySeries.nodes.mapPolygons.template.setAll({
|
|
1133
|
-
fill:
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1199
|
+
fill: espresso,
|
|
1200
|
+
stroke: crema,
|
|
1201
|
+
strokeWidth: 1.5,
|
|
1202
|
+
fillOpacity: 0.95,
|
|
1203
|
+
strokeOpacity: 1,
|
|
1204
|
+
tooltipText: "{name}\n{sum}k tonnes"
|
|
1137
1205
|
});
|
|
1138
1206
|
|
|
1139
|
-
//
|
|
1207
|
+
// Animated coffee bean bullets
|
|
1208
|
+
sankeySeries.bullets.push(function() {
|
|
1209
|
+
return am5.Bullet.new(root, {
|
|
1210
|
+
locationX: 0,
|
|
1211
|
+
autoRotate: true,
|
|
1212
|
+
sprite: am5.Graphics.new(root, {
|
|
1213
|
+
svgPath: "M-4,-2.5 C-4,-5 -1.5,-6.5 1,-6.5 C3.5,-6.5 5,-4.5 5,-2 C5,1 3,3.5 0.5,5 C-0.5,5.7 -1.5,5.7 -2.5,5 C-5,3.5 -6,1 -4,-2.5 Z M-1,-5 C-1,-1 -1,2 -0.5,4.5",
|
|
1214
|
+
fill: espresso,
|
|
1215
|
+
stroke: darkRoast,
|
|
1216
|
+
strokeWidth: 0.5,
|
|
1217
|
+
centerX: am5.p50,
|
|
1218
|
+
centerY: am5.p50,
|
|
1219
|
+
scale: 0.35,
|
|
1220
|
+
visible: false
|
|
1221
|
+
})
|
|
1222
|
+
});
|
|
1223
|
+
});
|
|
1224
|
+
|
|
1225
|
+
// Set data after polygonSeries loads (sourceId/targetId need centroid lookup)
|
|
1226
|
+
// CRITICAL: data MUST be set inside datavalidated handler
|
|
1140
1227
|
polygonSeries.events.once("datavalidated", function() {
|
|
1141
1228
|
sankeySeries.data.setAll([
|
|
1142
|
-
// Producers >
|
|
1229
|
+
// Producers > Hubs
|
|
1143
1230
|
{ sourceId: "BR", targetId: "DE", value: 350 },
|
|
1144
1231
|
{ sourceId: "BR", targetId: "US", value: 450 },
|
|
1145
|
-
{ sourceId: "
|
|
1146
|
-
{ sourceId: "
|
|
1147
|
-
{ sourceId: "
|
|
1148
|
-
{ sourceId: "
|
|
1149
|
-
|
|
1150
|
-
{ sourceId: "
|
|
1151
|
-
{ sourceId: "
|
|
1152
|
-
{ sourceId: "
|
|
1153
|
-
{ sourceId: "
|
|
1232
|
+
{ sourceId: "BR", targetId: "IT", value: 200 },
|
|
1233
|
+
{ sourceId: "VN", targetId: "DE", value: 200 },
|
|
1234
|
+
{ sourceId: "VN", targetId: "BE", value: 150 },
|
|
1235
|
+
{ sourceId: "CO", targetId: "US", value: 250 },
|
|
1236
|
+
{ sourceId: "CO", targetId: "DE", value: 80 },
|
|
1237
|
+
{ sourceId: "ET", targetId: "DE", value: 60 },
|
|
1238
|
+
{ sourceId: "ET", targetId: "BE", value: 40 },
|
|
1239
|
+
{ sourceId: "ID", targetId: "US", value: 80 },
|
|
1240
|
+
{ sourceId: "HN", targetId: "DE", value: 60 },
|
|
1241
|
+
{ sourceId: "HN", targetId: "BE", value: 40 },
|
|
1242
|
+
// Hubs > Consumer Markets
|
|
1243
|
+
{ sourceId: "DE", targetId: "FR", value: 150 },
|
|
1244
|
+
{ sourceId: "DE", targetId: "PL", value: 100 },
|
|
1245
|
+
{ sourceId: "DE", targetId: "SE", value: 80 },
|
|
1246
|
+
{ sourceId: "DE", targetId: "RU", value: 120 },
|
|
1247
|
+
{ sourceId: "BE", targetId: "GB", value: 100 },
|
|
1248
|
+
{ sourceId: "BE", targetId: "NL", value: 80 },
|
|
1249
|
+
{ sourceId: "IT", targetId: "GR", value: 50 },
|
|
1250
|
+
{ sourceId: "IT", targetId: "AT", value: 40 },
|
|
1251
|
+
{ sourceId: "US", targetId: "CA", value: 120 },
|
|
1252
|
+
{ sourceId: "US", targetId: "JP", value: 80 }
|
|
1154
1253
|
]);
|
|
1155
1254
|
});
|
|
1156
1255
|
|
|
1157
|
-
|
|
1256
|
+
// Set country names on auto-created nodes and animate bullets
|
|
1257
|
+
var countryNames = {
|
|
1258
|
+
BR: "Brazil", VN: "Vietnam", CO: "Colombia", ET: "Ethiopia",
|
|
1259
|
+
ID: "Indonesia", HN: "Honduras", DE: "Germany", BE: "Belgium",
|
|
1260
|
+
IT: "Italy", US: "United States", FR: "France", PL: "Poland",
|
|
1261
|
+
SE: "Sweden", RU: "Russia", GB: "United Kingdom", NL: "Netherlands",
|
|
1262
|
+
GR: "Greece", AT: "Austria", CA: "Canada", JP: "Japan"
|
|
1263
|
+
};
|
|
1264
|
+
|
|
1265
|
+
sankeySeries.events.on("datavalidated", function() {
|
|
1266
|
+
am5.array.each(sankeySeries.nodes.dataItems, function(di) {
|
|
1267
|
+
var id = di.get("id");
|
|
1268
|
+
if (id && countryNames[id]) {
|
|
1269
|
+
di.set("name", countryNames[id]);
|
|
1270
|
+
}
|
|
1271
|
+
});
|
|
1272
|
+
|
|
1273
|
+
// Defer bullet animation — bullets are not yet instantiated
|
|
1274
|
+
// when datavalidated fires inside polygonSeries handler
|
|
1275
|
+
setTimeout(function() {
|
|
1276
|
+
am5.array.each(sankeySeries.dataItems, function(dataItem) {
|
|
1277
|
+
var bullets = dataItem.bullets;
|
|
1278
|
+
if (bullets) {
|
|
1279
|
+
am5.array.each(bullets, function(bullet) {
|
|
1280
|
+
var randomDur = 3000 + Math.random() * 3000;
|
|
1281
|
+
var delay = Math.random() * randomDur;
|
|
1282
|
+
setTimeout(function() {
|
|
1283
|
+
var sprite = bullet.get("sprite");
|
|
1284
|
+
if (sprite) sprite.set("visible", true);
|
|
1285
|
+
bullet.animate({
|
|
1286
|
+
key: "locationX",
|
|
1287
|
+
from: 0,
|
|
1288
|
+
to: 1,
|
|
1289
|
+
duration: randomDur,
|
|
1290
|
+
easing: am5.ease.linear,
|
|
1291
|
+
loops: Infinity
|
|
1292
|
+
});
|
|
1293
|
+
}, delay);
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
});
|
|
1297
|
+
}, 100);
|
|
1298
|
+
});
|
|
1299
|
+
|
|
1300
|
+
// Title
|
|
1301
|
+
var titleCont = chart.children.push(am5.Container.new(root, {
|
|
1302
|
+
layout: root.verticalLayout,
|
|
1303
|
+
x: am5.p50, centerX: am5.p50,
|
|
1304
|
+
y: am5.p100, centerY: am5.p100,
|
|
1305
|
+
position: "absolute", paddingBottom: 16
|
|
1306
|
+
}));
|
|
1307
|
+
titleCont.children.push(am5.Label.new(root, {
|
|
1308
|
+
text: "Global Coffee Supply Chain",
|
|
1309
|
+
fontSize: 18, fontWeight: "600", fill: espresso,
|
|
1310
|
+
x: am5.p50, centerX: am5.p50
|
|
1311
|
+
}));
|
|
1312
|
+
titleCont.children.push(am5.Label.new(root, {
|
|
1313
|
+
text: "(Thousands of tonnes)",
|
|
1314
|
+
fontSize: 11, fill: mediumRoast,
|
|
1315
|
+
x: am5.p50, centerX: am5.p50
|
|
1316
|
+
}));
|
|
1317
|
+
|
|
1318
|
+
// Globe / Map toggle
|
|
1319
|
+
var switchCont = chart.children.push(am5.Container.new(root, {
|
|
1320
|
+
layout: root.horizontalLayout, x: 20, y: 40
|
|
1321
|
+
}));
|
|
1322
|
+
switchCont.children.push(am5.Label.new(root, {
|
|
1323
|
+
centerY: am5.p50, text: "Globe", fill: espresso, fontSize: 13
|
|
1324
|
+
}));
|
|
1325
|
+
var switchButton = switchCont.children.push(am5.Button.new(root, {
|
|
1326
|
+
themeTags: ["switch"], centerY: am5.p50,
|
|
1327
|
+
icon: am5.Circle.new(root, { themeTags: ["icon"] })
|
|
1328
|
+
}));
|
|
1329
|
+
|
|
1330
|
+
var easing = am5.ease.inOut(am5.ease.cubic);
|
|
1331
|
+
var duration = 1500;
|
|
1332
|
+
var fadeDuration = 300;
|
|
1333
|
+
|
|
1334
|
+
function zoomToGlobe() {
|
|
1335
|
+
chart.set("projection", am5map.geoOrthographic());
|
|
1336
|
+
chart.set("panX", "rotateX");
|
|
1337
|
+
chart.set("panY", "rotateY");
|
|
1338
|
+
chart.animate({ key: "rotationX", to: -15, duration: duration, easing: easing });
|
|
1339
|
+
chart.animate({ key: "rotationY", to: -20, duration: duration, easing: easing });
|
|
1340
|
+
bgSeries.mapPolygons.template.set("fillOpacity", 1);
|
|
1341
|
+
chart.set("minZoomLevel", 0.9);
|
|
1342
|
+
chart.animate({ key: "zoomLevel", to: 0.9, duration: duration, easing: easing });
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
function zoomToMap() {
|
|
1346
|
+
chart.set("projection", am5map.geoMercator());
|
|
1347
|
+
chart.set("panX", "translateX");
|
|
1348
|
+
chart.set("panY", "translateY");
|
|
1349
|
+
chart.animate({ key: "rotationX", to: 0, duration: duration, easing: easing });
|
|
1350
|
+
chart.animate({ key: "rotationY", to: 0, duration: duration, easing: easing });
|
|
1351
|
+
bgSeries.mapPolygons.template.set("fillOpacity", 0);
|
|
1352
|
+
chart.set("minZoomLevel", 1);
|
|
1353
|
+
chart.animate({ key: "zoomLevel", to: 1.7, duration: duration, easing: easing });
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
switchButton.on("active", function() {
|
|
1357
|
+
chart.goHome(duration);
|
|
1358
|
+
setTimeout(function() {
|
|
1359
|
+
chart.seriesContainer.animate({ key: "opacity", to: 0, duration: fadeDuration });
|
|
1360
|
+
}, duration - fadeDuration);
|
|
1361
|
+
setTimeout(function() {
|
|
1362
|
+
if (switchButton.get("active")) { zoomToMap(); } else { zoomToGlobe(); }
|
|
1363
|
+
chart.seriesContainer.animate({ key: "opacity", to: 1, duration: fadeDuration });
|
|
1364
|
+
}, duration);
|
|
1365
|
+
});
|
|
1366
|
+
|
|
1367
|
+
switchCont.children.push(am5.Label.new(root, {
|
|
1368
|
+
centerY: am5.p50, text: "Map", fill: espresso, fontSize: 13
|
|
1369
|
+
}));
|
|
1370
|
+
|
|
1371
|
+
// Zoom controls
|
|
1372
|
+
var zoomControl = chart.set("zoomControl", am5map.ZoomControl.new(root, {}));
|
|
1373
|
+
zoomControl.homeButton.set("visible", true);
|
|
1374
|
+
|
|
1375
|
+
// Auto-rotate globe until user interaction
|
|
1376
|
+
var rotationAnimation = chart.animate({
|
|
1377
|
+
key: "rotationX", from: -15, to: -15 + 360,
|
|
1378
|
+
duration: 120000, loops: Infinity, easing: am5.ease.linear
|
|
1379
|
+
});
|
|
1380
|
+
chart.chartContainer.events.on("pointerdown", function() {
|
|
1381
|
+
if (rotationAnimation) { rotationAnimation.stop(); rotationAnimation = null; }
|
|
1382
|
+
});
|
|
1383
|
+
|
|
1158
1384
|
chart.appear(1000, 100);
|
|
1159
1385
|
</script>
|
|
1160
1386
|
</body>
|
|
1161
1387
|
</html>
|
|
1162
1388
|
```
|
|
1163
1389
|
|
|
1164
|
-
## Example 6: Map Sankey —
|
|
1390
|
+
## Example 6: Map Sankey — Oil Export Flows with Waypoints (explicit coordinates)
|
|
1391
|
+
|
|
1392
|
+
Demonstrates: `MapSankeySeries` with explicit `sourceLongitude`/`sourceLatitude` coordinates, maritime waypoints for realistic shipping routes, oil drop SVG bullets with proportional animation speed, dark theme, country highlighting, and Globe/Map projection toggle. Based on the `map-sankey-waypoints` shared example.
|
|
1165
1393
|
|
|
1166
|
-
|
|
1394
|
+
**IMPORTANT — waypoints must use `longitude`/`latitude` keys** (not shorthand like `lon`/`lat`). Source/target location objects can use any keys because the `flow()` helper maps them to `sourceLongitude`/`sourceLatitude`, but waypoints are read directly by the series via `wp.longitude` and `wp.latitude`.
|
|
1167
1395
|
|
|
1168
1396
|
```html
|
|
1169
1397
|
<!DOCTYPE html>
|
|
1170
1398
|
<html>
|
|
1171
1399
|
<head>
|
|
1172
1400
|
<meta charset="UTF-8">
|
|
1173
|
-
<title>Map Sankey — Oil Flows</title>
|
|
1401
|
+
<title>Map Sankey — Oil Export Flows</title>
|
|
1174
1402
|
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
|
|
1175
1403
|
<script src="https://cdn.amcharts.com/lib/5/map.js"></script>
|
|
1176
1404
|
<script src="https://cdn.amcharts.com/lib/5/geodata/worldLow.js"></script>
|
|
1177
1405
|
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
|
|
1178
|
-
<style>body {
|
|
1406
|
+
<style>body { margin: 0; background: #0a0e12; } #chartdiv { width: 100%; height: 600px; }</style>
|
|
1179
1407
|
</head>
|
|
1180
1408
|
<body>
|
|
1181
1409
|
<div id="chartdiv"></div>
|
|
1182
1410
|
<script>
|
|
1183
1411
|
var root = am5.Root.new("chartdiv");
|
|
1184
|
-
|
|
1412
|
+
|
|
1413
|
+
// Oil/dark theme
|
|
1414
|
+
var oilTheme = am5.Theme.new(root);
|
|
1415
|
+
oilTheme.rule("InterfaceColors").setAll({
|
|
1416
|
+
primaryButton: am5.color(0x1e2824),
|
|
1417
|
+
primaryButtonHover: am5.color(0x3a5040),
|
|
1418
|
+
primaryButtonDown: am5.color(0x0a0e12),
|
|
1419
|
+
primaryButtonActive: am5.color(0xc8890a),
|
|
1420
|
+
primaryButtonText: am5.color(0xf5d090),
|
|
1421
|
+
secondaryButton: am5.color(0x1e2824),
|
|
1422
|
+
secondaryButtonHover: am5.color(0x3a5040),
|
|
1423
|
+
secondaryButtonDown: am5.color(0x141a1a),
|
|
1424
|
+
secondaryButtonText: am5.color(0xf5d090),
|
|
1425
|
+
background: am5.color(0x0a0e12),
|
|
1426
|
+
text: am5.color(0xf5d090)
|
|
1427
|
+
});
|
|
1428
|
+
root.setThemes([am5themes_Animated.new(root), oilTheme]);
|
|
1429
|
+
|
|
1430
|
+
// Palette
|
|
1431
|
+
var deepCrude = am5.color(0x141a1a);
|
|
1432
|
+
var slick = am5.color(0x1e2824);
|
|
1433
|
+
var pipeline = am5.color(0x3a5040);
|
|
1434
|
+
var amber = am5.color(0xc8890a);
|
|
1435
|
+
var sulfur = am5.color(0xa89050);
|
|
1436
|
+
var flare = am5.color(0xf5d090);
|
|
1185
1437
|
|
|
1186
1438
|
var chart = root.container.children.push(am5map.MapChart.new(root, {
|
|
1187
1439
|
panX: "rotateX",
|
|
1188
1440
|
panY: "rotateY",
|
|
1189
1441
|
projection: am5map.geoOrthographic(),
|
|
1190
|
-
|
|
1191
|
-
|
|
1442
|
+
homeGeoPoint: { longitude: 0, latitude: 0 },
|
|
1443
|
+
homeRotationX: 0,
|
|
1444
|
+
homeRotationY: 0,
|
|
1445
|
+
homeZoomLevel: 1,
|
|
1446
|
+
minZoomLevel: 0.8,
|
|
1447
|
+
zoomLevel: 1
|
|
1192
1448
|
}));
|
|
1193
1449
|
|
|
1450
|
+
// Ocean
|
|
1194
1451
|
var bgSeries = chart.series.push(am5map.MapPolygonSeries.new(root, {}));
|
|
1195
|
-
bgSeries.mapPolygons.template.setAll({
|
|
1452
|
+
bgSeries.mapPolygons.template.setAll({
|
|
1453
|
+
fill: deepCrude, fillOpacity: 1, strokeOpacity: 0
|
|
1454
|
+
});
|
|
1196
1455
|
bgSeries.data.push({ geometry: am5map.getGeoRectangle(90, 180, -90, -180) });
|
|
1197
1456
|
|
|
1457
|
+
// Graticule
|
|
1458
|
+
var graticuleSeries = chart.series.push(am5map.GraticuleSeries.new(root, {}));
|
|
1459
|
+
graticuleSeries.mapLines.template.setAll({
|
|
1460
|
+
stroke: pipeline, strokeOpacity: 0.25, strokeWidth: 0.5
|
|
1461
|
+
});
|
|
1462
|
+
|
|
1463
|
+
// Countries
|
|
1198
1464
|
var polygonSeries = chart.series.push(am5map.MapPolygonSeries.new(root, {
|
|
1199
1465
|
geoJSON: am5geodata_worldLow
|
|
1200
1466
|
}));
|
|
1201
1467
|
polygonSeries.mapPolygons.template.setAll({
|
|
1202
|
-
fill:
|
|
1203
|
-
stroke: am5.color(0x1a2a3a),
|
|
1204
|
-
strokeWidth: 0.5
|
|
1468
|
+
fill: slick, stroke: pipeline, strokeWidth: 0.5, strokeOpacity: 0.6
|
|
1205
1469
|
});
|
|
1206
1470
|
|
|
1471
|
+
// Highlight producer & importer countries
|
|
1472
|
+
var producerIds = ["SA", "IQ", "AE", "KW", "IR", "QA"];
|
|
1473
|
+
var importerIds = ["CN", "JP", "KR", "IN", "SG", "IT", "GR", "NL"];
|
|
1474
|
+
polygonSeries.events.on("datavalidated", function() {
|
|
1475
|
+
am5.array.each(polygonSeries.dataItems, function(di) {
|
|
1476
|
+
var id = di.get("id");
|
|
1477
|
+
if (producerIds.indexOf(id) !== -1) {
|
|
1478
|
+
di.get("mapPolygon").setAll({ fill: am5.color(0x6b5a10), tooltipText: "{name}" });
|
|
1479
|
+
} else if (importerIds.indexOf(id) !== -1) {
|
|
1480
|
+
di.get("mapPolygon").setAll({ fill: am5.color(0x2a4030), tooltipText: "{name}" });
|
|
1481
|
+
}
|
|
1482
|
+
});
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1485
|
+
// MapSankeySeries
|
|
1207
1486
|
var sankeySeries = chart.series.push(am5map.MapSankeySeries.new(root, {
|
|
1208
1487
|
polygonSeries: polygonSeries,
|
|
1209
|
-
maxWidth:
|
|
1210
|
-
controlPointDistance: 0.
|
|
1211
|
-
resolution: 60
|
|
1488
|
+
maxWidth: 0.8,
|
|
1489
|
+
controlPointDistance: 0.4,
|
|
1490
|
+
resolution: 60,
|
|
1491
|
+
nodePadding: 0.1
|
|
1212
1492
|
}));
|
|
1213
1493
|
|
|
1214
1494
|
sankeySeries.mapPolygons.template.setAll({
|
|
1215
|
-
fill:
|
|
1216
|
-
|
|
1217
|
-
strokeOpacity: 0,
|
|
1218
|
-
tooltipText: "{source} > {target}: {value}M barrels/day"
|
|
1495
|
+
fill: amber, fillOpacity: 0.4, strokeOpacity: 0,
|
|
1496
|
+
tooltipText: "{source} > {target}\n{value}k bbl/day"
|
|
1219
1497
|
});
|
|
1220
1498
|
|
|
1221
1499
|
sankeySeries.nodes.mapPolygons.template.setAll({
|
|
1222
|
-
fill:
|
|
1223
|
-
|
|
1224
|
-
strokeWidth: 1.5,
|
|
1225
|
-
fillOpacity: 0.9,
|
|
1226
|
-
tooltipText: "{name}"
|
|
1500
|
+
fill: amber, stroke: flare, strokeWidth: 1.5,
|
|
1501
|
+
fillOpacity: 0.95, strokeOpacity: 1, tooltipText: "{name}"
|
|
1227
1502
|
});
|
|
1228
1503
|
|
|
1229
|
-
//
|
|
1230
|
-
function flow(src, srcName, tgt, tgtName, val, wp) {
|
|
1231
|
-
var result = {
|
|
1232
|
-
sourceLongitude: src.lon, sourceLatitude: src.lat,
|
|
1233
|
-
targetLongitude: tgt.lon, targetLatitude: tgt.lat,
|
|
1234
|
-
source: srcName, target: tgtName, value: val
|
|
1235
|
-
};
|
|
1236
|
-
if (wp) result.waypoints = wp;
|
|
1237
|
-
return result;
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
var saudiPort = { lon: 50.2, lat: 26.6 };
|
|
1241
|
-
var hormuz = { lon: 56.3, lat: 26.6 };
|
|
1242
|
-
var india = { lon: 72.8, lat: 19.1 };
|
|
1243
|
-
var china = { lon: 121.5, lat: 31.2 };
|
|
1244
|
-
var japan = { lon: 139.7, lat: 35.7 };
|
|
1245
|
-
var europe = { lon: 9.5, lat: 44.4 };
|
|
1246
|
-
var suez = { lon: 32.3, lat: 30.0 };
|
|
1247
|
-
|
|
1248
|
-
// No datavalidated wrapper needed — explicit coordinates resolve immediately
|
|
1249
|
-
sankeySeries.data.setAll([
|
|
1250
|
-
flow(saudiPort, "Saudi Arabia", china, "China", 1.8,
|
|
1251
|
-
[hormuz, { lon: 65, lat: 20 }, { lon: 80, lat: 15 }, { lon: 105, lat: 20 }]),
|
|
1252
|
-
flow(saudiPort, "Saudi Arabia", japan, "Japan", 1.2,
|
|
1253
|
-
[hormuz, { lon: 70, lat: 22 }, { lon: 100, lat: 18 }, { lon: 125, lat: 28 }]),
|
|
1254
|
-
flow(saudiPort, "Saudi Arabia", india, "India", 0.9,
|
|
1255
|
-
[hormuz, { lon: 62, lat: 22 }]),
|
|
1256
|
-
flow(saudiPort, "Saudi Arabia", europe, "Europe", 1.0,
|
|
1257
|
-
[{ lon: 43, lat: 28 }, suez, { lon: 20, lat: 36 }])
|
|
1258
|
-
]);
|
|
1259
|
-
|
|
1260
|
-
// Animated bullets along flow paths
|
|
1504
|
+
// Animated oil drop bullets
|
|
1261
1505
|
sankeySeries.bullets.push(function() {
|
|
1262
1506
|
return am5.Bullet.new(root, {
|
|
1263
1507
|
locationX: 0,
|
|
1264
1508
|
autoRotate: true,
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1509
|
+
autoRotateAngle: -90,
|
|
1510
|
+
sprite: am5.Graphics.new(root, {
|
|
1511
|
+
svgPath: "M0,-7 C2,-4 5,0 5,3 C5,6 3,8 0,8 C-3,8 -5,6 -5,3 C-5,0 -2,-4 0,-7 Z",
|
|
1512
|
+
fill: amber, stroke: am5.color(0x8b6914), strokeWidth: 0.5,
|
|
1513
|
+
centerX: am5.p50, centerY: am5.p50, scale: 0.45, visible: false
|
|
1268
1514
|
})
|
|
1269
1515
|
});
|
|
1270
1516
|
});
|
|
1271
1517
|
|
|
1272
1518
|
sankeySeries.events.on("datavalidated", function() {
|
|
1519
|
+
// Scale animation duration proportionally to path length
|
|
1520
|
+
var maxLength = 0;
|
|
1273
1521
|
am5.array.each(sankeySeries.dataItems, function(dataItem) {
|
|
1522
|
+
var len = sankeySeries.getPathLength(dataItem);
|
|
1523
|
+
if (len > maxLength) maxLength = len;
|
|
1524
|
+
});
|
|
1525
|
+
|
|
1526
|
+
var baseDuration = 8000;
|
|
1527
|
+
var minDuration = 2000;
|
|
1528
|
+
|
|
1529
|
+
am5.array.each(sankeySeries.dataItems, function(dataItem) {
|
|
1530
|
+
var pathLength = sankeySeries.getPathLength(dataItem) || maxLength;
|
|
1531
|
+
var dur = maxLength > 0
|
|
1532
|
+
? Math.max(minDuration, (pathLength / maxLength) * baseDuration)
|
|
1533
|
+
: baseDuration;
|
|
1274
1534
|
var bullets = dataItem.bullets;
|
|
1275
1535
|
if (bullets) {
|
|
1276
1536
|
am5.array.each(bullets, function(bullet) {
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1537
|
+
var randomDur = dur * (0.8 + Math.random() * 0.4);
|
|
1538
|
+
var delay = Math.random() * randomDur;
|
|
1539
|
+
setTimeout(function() {
|
|
1540
|
+
var sprite = bullet.get("sprite");
|
|
1541
|
+
if (sprite) sprite.set("visible", true);
|
|
1542
|
+
bullet.animate({
|
|
1543
|
+
key: "locationX", from: 0, to: 1,
|
|
1544
|
+
duration: randomDur, easing: am5.ease.linear, loops: Infinity
|
|
1545
|
+
});
|
|
1546
|
+
}, delay);
|
|
1284
1547
|
});
|
|
1285
1548
|
}
|
|
1286
1549
|
});
|
|
1287
1550
|
});
|
|
1288
1551
|
|
|
1289
|
-
|
|
1552
|
+
// Gulf export terminals (source/target objects can use any key names
|
|
1553
|
+
// because the flow() helper maps them to sourceLongitude/sourceLatitude)
|
|
1554
|
+
var rasTanura = { lon: 50.17, lat: 26.64 };
|
|
1555
|
+
var basra = { lon: 48.80, lat: 29.69 };
|
|
1556
|
+
var fujairah = { lon: 56.33, lat: 25.12 };
|
|
1557
|
+
var minaAhmadi = { lon: 48.17, lat: 29.08 };
|
|
1558
|
+
var khargIsland = { lon: 50.32, lat: 29.23 };
|
|
1559
|
+
var rasLaffan = { lon: 51.56, lat: 25.93 };
|
|
1560
|
+
|
|
1561
|
+
// Import terminals
|
|
1562
|
+
var ningbo = { lon: 121.97, lat: 29.87 };
|
|
1563
|
+
var qingdao = { lon: 120.38, lat: 36.07 };
|
|
1564
|
+
var yokohama = { lon: 139.64, lat: 35.44 };
|
|
1565
|
+
var chiba = { lon: 140.10, lat: 35.60 };
|
|
1566
|
+
var ulsan = { lon: 129.38, lat: 35.50 };
|
|
1567
|
+
var jamnagar = { lon: 69.66, lat: 22.42 };
|
|
1568
|
+
var mumbai = { lon: 72.88, lat: 19.08 };
|
|
1569
|
+
var singapore = { lon: 103.84, lat: 1.26 };
|
|
1570
|
+
var trieste = { lon: 13.78, lat: 45.65 };
|
|
1571
|
+
var piraeus = { lon: 23.63, lat: 37.94 };
|
|
1572
|
+
var rotterdam = { lon: 4.12, lat: 51.95 };
|
|
1573
|
+
|
|
1574
|
+
function flow(src, srcName, tgt, tgtName, value, wp) {
|
|
1575
|
+
var result = {
|
|
1576
|
+
sourceLongitude: src.lon, sourceLatitude: src.lat,
|
|
1577
|
+
targetLongitude: tgt.lon, targetLatitude: tgt.lat,
|
|
1578
|
+
source: srcName, target: tgtName, value: value
|
|
1579
|
+
};
|
|
1580
|
+
if (wp) result.waypoints = wp;
|
|
1581
|
+
return result;
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
// IMPORTANT: waypoints must use { longitude: ..., latitude: ... }
|
|
1585
|
+
// (NOT shorthand like { lon, lat }) — the series reads wp.longitude / wp.latitude directly
|
|
1586
|
+
var wpHormuz = { longitude: 58, latitude: 24 };
|
|
1587
|
+
var wpArabianSea = { longitude: 64, latitude: 18 };
|
|
1588
|
+
var wpSouthIndia = { longitude: 78, latitude: 6 };
|
|
1589
|
+
var wpMalacca = { longitude: 101, latitude: 3 };
|
|
1590
|
+
var wpAden = { longitude: 47, latitude: 12 };
|
|
1591
|
+
var wpSuez = { longitude: 34, latitude: 29 };
|
|
1592
|
+
|
|
1593
|
+
// Route templates
|
|
1594
|
+
var viaJapan = [{ longitude: 58, latitude: 26 }, { longitude: 80, latitude: 9 }, { longitude: 104, latitude: 7 }];
|
|
1595
|
+
var viaKorea = [{ longitude: 58, latitude: 24 }, { longitude: 78, latitude: 6 }, { longitude: 101, latitude: 3 }];
|
|
1596
|
+
var viaChina = [{ longitude: 58, latitude: 22 }, { longitude: 76, latitude: 3 }, { longitude: 99, latitude: 1 }];
|
|
1597
|
+
var viaChinaNorth = [{ longitude: 58, latitude: 22 }, { longitude: 76, latitude: 3 }, { longitude: 99, latitude: 1 }, { longitude: 124, latitude: 32 }];
|
|
1598
|
+
var viaIndiaNear = [wpHormuz];
|
|
1599
|
+
var viaIndiaFar = [wpHormuz, wpArabianSea];
|
|
1600
|
+
var viaSingapore = [wpHormuz, wpSouthIndia];
|
|
1601
|
+
var viaSuez = [wpHormuz, wpAden, wpSuez];
|
|
1602
|
+
var wpSouthGreece = { longitude: 22, latitude: 35 };
|
|
1603
|
+
var wpOtranto = { longitude: 18.5, latitude: 40 };
|
|
1604
|
+
var viaSuezItaly = [wpHormuz, wpAden, wpSuez, wpSouthGreece, wpOtranto];
|
|
1605
|
+
var wpSicily = { longitude: 13, latitude: 37 };
|
|
1606
|
+
var wpPortugal = { longitude: -10, latitude: 39 };
|
|
1607
|
+
var viaAtlantic = [wpHormuz, wpAden, wpSuez, wpSicily, wpPortugal];
|
|
1608
|
+
|
|
1609
|
+
// No datavalidated wrapper needed — explicit coordinates resolve immediately
|
|
1610
|
+
sankeySeries.data.setAll([
|
|
1611
|
+
// Ras Tanura (Saudi Arabia)
|
|
1612
|
+
flow(rasTanura, "Ras Tanura", ningbo, "Ningbo", 1100, viaChina),
|
|
1613
|
+
flow(rasTanura, "Ras Tanura", qingdao, "Qingdao", 600, viaChinaNorth),
|
|
1614
|
+
flow(rasTanura, "Ras Tanura", yokohama, "Yokohama", 700, viaJapan),
|
|
1615
|
+
flow(rasTanura, "Ras Tanura", chiba, "Chiba", 300, viaJapan),
|
|
1616
|
+
flow(rasTanura, "Ras Tanura", ulsan, "Ulsan", 800, viaKorea),
|
|
1617
|
+
flow(rasTanura, "Ras Tanura", jamnagar, "Jamnagar", 500, viaIndiaNear),
|
|
1618
|
+
flow(rasTanura, "Ras Tanura", mumbai, "Mumbai", 300, viaIndiaFar),
|
|
1619
|
+
flow(rasTanura, "Ras Tanura", rotterdam, "Rotterdam", 350, viaAtlantic),
|
|
1620
|
+
// Basra Oil Terminal (Iraq)
|
|
1621
|
+
flow(basra, "Basra", ningbo, "Ningbo", 700, viaChina),
|
|
1622
|
+
flow(basra, "Basra", qingdao, "Qingdao", 400, viaChinaNorth),
|
|
1623
|
+
flow(basra, "Basra", jamnagar, "Jamnagar", 600, viaIndiaNear),
|
|
1624
|
+
flow(basra, "Basra", mumbai, "Mumbai", 400, viaIndiaFar),
|
|
1625
|
+
flow(basra, "Basra", ulsan, "Ulsan", 400, viaKorea),
|
|
1626
|
+
flow(basra, "Basra", trieste, "Trieste", 350, viaSuezItaly),
|
|
1627
|
+
flow(basra, "Basra", piraeus, "Piraeus", 250, viaSuez),
|
|
1628
|
+
// Fujairah (UAE) — already outside Hormuz
|
|
1629
|
+
flow(fujairah, "Fujairah", yokohama, "Yokohama", 400, viaJapan.slice(1)),
|
|
1630
|
+
flow(fujairah, "Fujairah", chiba, "Chiba", 200, viaJapan.slice(1)),
|
|
1631
|
+
flow(fujairah, "Fujairah", jamnagar, "Jamnagar", 300),
|
|
1632
|
+
flow(fujairah, "Fujairah", mumbai, "Mumbai", 200, [wpArabianSea]),
|
|
1633
|
+
flow(fujairah, "Fujairah", ningbo, "Ningbo", 250, viaChina.slice(1)),
|
|
1634
|
+
flow(fujairah, "Fujairah", ulsan, "Ulsan", 350, viaKorea.slice(1)),
|
|
1635
|
+
flow(fujairah, "Fujairah", singapore, "Singapore", 250, [wpSouthIndia]),
|
|
1636
|
+
// Mina Al Ahmadi (Kuwait)
|
|
1637
|
+
flow(minaAhmadi, "Mina Al Ahmadi", ulsan, "Ulsan", 400, viaKorea),
|
|
1638
|
+
flow(minaAhmadi, "Mina Al Ahmadi", yokohama, "Yokohama", 300, viaJapan),
|
|
1639
|
+
flow(minaAhmadi, "Mina Al Ahmadi", ningbo, "Ningbo", 300, viaChina),
|
|
1640
|
+
flow(minaAhmadi, "Mina Al Ahmadi", jamnagar, "Jamnagar", 200, viaIndiaNear),
|
|
1641
|
+
// Kharg Island (Iran)
|
|
1642
|
+
flow(khargIsland, "Kharg Island", ningbo, "Ningbo", 400, viaChina),
|
|
1643
|
+
flow(khargIsland, "Kharg Island", qingdao, "Qingdao", 200, viaChinaNorth),
|
|
1644
|
+
flow(khargIsland, "Kharg Island", jamnagar, "Jamnagar", 200, viaIndiaNear),
|
|
1645
|
+
flow(khargIsland, "Kharg Island", piraeus, "Piraeus", 100, viaSuez),
|
|
1646
|
+
// Ras Laffan (Qatar)
|
|
1647
|
+
flow(rasLaffan, "Ras Laffan", yokohama, "Yokohama", 300, viaJapan),
|
|
1648
|
+
flow(rasLaffan, "Ras Laffan", ulsan, "Ulsan", 200, viaKorea),
|
|
1649
|
+
flow(rasLaffan, "Ras Laffan", jamnagar, "Jamnagar", 150, viaIndiaNear),
|
|
1650
|
+
flow(rasLaffan, "Ras Laffan", singapore,"Singapore", 120, viaSingapore)
|
|
1651
|
+
]);
|
|
1652
|
+
|
|
1653
|
+
// Title
|
|
1654
|
+
var titleCont = chart.children.push(am5.Container.new(root, {
|
|
1655
|
+
layout: root.verticalLayout,
|
|
1656
|
+
x: am5.p50, centerX: am5.p50, y: 0,
|
|
1657
|
+
position: "absolute", paddingTop: 16
|
|
1658
|
+
}));
|
|
1659
|
+
titleCont.children.push(am5.Label.new(root, {
|
|
1660
|
+
text: "Strait of Hormuz — Oil Export Flows",
|
|
1661
|
+
fontSize: 18, fontWeight: "600", fill: amber,
|
|
1662
|
+
x: am5.p50, centerX: am5.p50
|
|
1663
|
+
}));
|
|
1664
|
+
titleCont.children.push(am5.Label.new(root, {
|
|
1665
|
+
text: "Gulf Producers > Major Importers (thousands of barrels/day)",
|
|
1666
|
+
fontSize: 11, fill: sulfur,
|
|
1667
|
+
x: am5.p50, centerX: am5.p50
|
|
1668
|
+
}));
|
|
1669
|
+
|
|
1670
|
+
// Globe / Map toggle
|
|
1671
|
+
var switchCont = chart.children.push(am5.Container.new(root, {
|
|
1672
|
+
layout: root.horizontalLayout, x: 20, y: 40
|
|
1673
|
+
}));
|
|
1674
|
+
switchCont.children.push(am5.Label.new(root, {
|
|
1675
|
+
centerY: am5.p50, text: "Globe", fill: flare, fontSize: 13
|
|
1676
|
+
}));
|
|
1677
|
+
var switchButton = switchCont.children.push(am5.Button.new(root, {
|
|
1678
|
+
themeTags: ["switch"], centerY: am5.p50,
|
|
1679
|
+
icon: am5.Circle.new(root, { themeTags: ["icon"] })
|
|
1680
|
+
}));
|
|
1681
|
+
|
|
1682
|
+
var easing = am5.ease.inOut(am5.ease.cubic);
|
|
1683
|
+
var duration = 1500;
|
|
1684
|
+
var fadeDuration = 300;
|
|
1685
|
+
|
|
1686
|
+
function zoomToGlobe() {
|
|
1687
|
+
chart.set("projection", am5map.geoOrthographic());
|
|
1688
|
+
chart.set("panX", "rotateX");
|
|
1689
|
+
chart.set("panY", "rotateY");
|
|
1690
|
+
chart.animate({ key: "rotationX", to: -74, duration: duration, easing: easing });
|
|
1691
|
+
chart.animate({ key: "rotationY", to: -30, duration: duration, easing: easing });
|
|
1692
|
+
chart.animate({ key: "zoomLevel", to: 1.6, duration: duration, easing: easing });
|
|
1693
|
+
bgSeries.mapPolygons.template.set("fillOpacity", 1);
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
function zoomToMap() {
|
|
1697
|
+
chart.set("projection", am5map.geoMercator());
|
|
1698
|
+
chart.set("panX", "translateX");
|
|
1699
|
+
chart.set("panY", "translateY");
|
|
1700
|
+
chart.animate({ key: "rotationY", to: 0, duration: duration, easing: easing });
|
|
1701
|
+
setTimeout(function() {
|
|
1702
|
+
chart.zoomToGeoPoint({ longitude: 67, latitude: 32 }, 3.5, true, duration);
|
|
1703
|
+
}, 100);
|
|
1704
|
+
bgSeries.mapPolygons.template.set("fillOpacity", 0);
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
switchButton.on("active", function() {
|
|
1708
|
+
chart.goHome(duration);
|
|
1709
|
+
setTimeout(function() {
|
|
1710
|
+
chart.seriesContainer.animate({ key: "opacity", to: 0, duration: fadeDuration });
|
|
1711
|
+
}, duration - fadeDuration);
|
|
1712
|
+
setTimeout(function() {
|
|
1713
|
+
if (switchButton.get("active")) { zoomToMap(); } else { zoomToGlobe(); }
|
|
1714
|
+
chart.seriesContainer.animate({ key: "opacity", to: 1, duration: fadeDuration });
|
|
1715
|
+
}, duration);
|
|
1716
|
+
});
|
|
1717
|
+
|
|
1718
|
+
switchCont.children.push(am5.Label.new(root, {
|
|
1719
|
+
centerY: am5.p50, text: "Map", fill: flare, fontSize: 13
|
|
1720
|
+
}));
|
|
1721
|
+
|
|
1722
|
+
// Zoom controls
|
|
1723
|
+
var zoomControl = chart.set("zoomControl", am5map.ZoomControl.new(root, {}));
|
|
1724
|
+
zoomControl.homeButton.set("visible", true);
|
|
1725
|
+
|
|
1290
1726
|
chart.appear(1000, 100);
|
|
1727
|
+
|
|
1728
|
+
// Initial animation: rotate to globe position
|
|
1729
|
+
setTimeout(function() { zoomToGlobe(); }, 1000);
|
|
1291
1730
|
</script>
|
|
1292
1731
|
</body>
|
|
1293
1732
|
</html>
|