Skip to content

Commit d098f31

Browse files
authored
Merge branch 'Azure-Samples:main' into main
2 parents 5d07669 + 7b7d887 commit d098f31

1,283 files changed

Lines changed: 120981 additions & 430697 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Build/SampleBuilder/SampleBuilder.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net8.0</TargetFramework>
5+
<TargetFramework>net9.0</TargetFramework>
66
<ImplicitUsings>enable</ImplicitUsings>
77
<Nullable>disable</Nullable>
88
<FileVersion>1.3.0.0</FileVersion>
99
<AssemblyVersion>1.3.0.0</AssemblyVersion>
1010
</PropertyGroup>
1111

1212
<ItemGroup>
13-
<PackageReference Include="HtmlAgilityPack" Version="1.11.58" />
14-
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
15-
<PackageReference Include="xsitemap" Version="2.9.3" />
13+
<PackageReference Include="HtmlAgilityPack" Version="1.12.0" />
14+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.3" />
15+
<PackageReference Include="X.Web.Sitemap" Version="2.10.5" />
1616
</ItemGroup>
1717

1818
<ItemGroup>

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ A collection of over a hundred code samples for the [Azure Maps](https://azurema
99
## Related Projects
1010

1111
* [Azure Maps Web SDK Open modules](https://github.com/microsoft/Maps/blob/master/AzureMaps.md#open-web-sdk-modules) - A collection of open source modules that extend the Azure Maps Web SDK.
12-
* [Azure Maps & Azure Active Directory Samples](https://github.com/Azure-Samples/Azure-Maps-AzureAD-Samples)
12+
* [Azure Maps & Microsoft Entra ID Samples](https://github.com/Azure-Samples/Azure-Maps-AzureAD-Samples)
1313
* [List of open-source Azure Maps projects](https://github.com/microsoft/Maps/blob/master/AzureMaps.md)
1414

1515
## Additional Resources

Samples/3D-layer/3D Elevation_experimental/3D Elevation.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@
4141

4242
// Add authentication details for connecting to Azure Maps
4343
authOptions: {
44-
// Use Azure Active Directory authentication in production
44+
// Use Microsoft Entra ID authentication in production
4545
authType: 'anonymous',
4646
clientId: 'e6b6ab59-eb5d-4d25-aa57-581135b927f0', // Your Azure Maps client id for accessing your Azure Maps account
4747
getToken: function (resolve, reject, map) {
48-
// URL to your authentication service that retrieves an Azure Active Directory Token
48+
// URL to your authentication service that retrieves an Microsoft Entra ID Token
4949
fetch('https://samples.azuremaps.com/api/GetAzureMapsToken')
5050
.then(function (response) {
5151
return response.text();
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Integration with Flowmap.gl - Azure Maps Web SDK Samples</title>
5+
6+
<meta charset="UTF-8" />
7+
<link rel="shortcut icon" href="/favicon.ico"/>
8+
9+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
10+
<meta name="description" content="This sample shows a flow map on top of Azure Maps using the flowmap.gl module." />
11+
<meta name="keywords" content="Microsoft maps, maps, map, API, SDK, flow map, flowmap, routing, data movement" />
12+
<meta name="author" content="Microsoft Azure Maps" /><meta name="version" content="1.0" />
13+
<meta name="screenshot" content="screenshot.jpg" />
14+
15+
<!-- Add reference to the Azure Maps Map control CSS file. -->
16+
<link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/3/atlas.min.css" rel="stylesheet" />
17+
18+
<!-- Add reference to the JavaScript file that integrates the Flowmap.gl module. -->
19+
<script type="module" crossorigin src="/3d-layer/flowmap.gl/build/index-6501962d.js"></script>
20+
21+
<style>
22+
.sidePanel {
23+
width: 350px;
24+
height: 580px;
25+
float: left;
26+
margin-right: 10px;
27+
}
28+
29+
#container {
30+
position: fixed;
31+
top: 0;
32+
left: 0;
33+
right: 0;
34+
bottom: 0;
35+
background: #000;
36+
position: relative;
37+
width: calc(100% - 360px);
38+
min-width:290px;
39+
height: 600px;
40+
float: left;
41+
}
42+
43+
#container > * {
44+
position: absolute;
45+
top: 0;
46+
left: 0;
47+
width: 100%;
48+
height: 100%;
49+
}
50+
51+
.atlas-map-canvas-container {
52+
opacity: 0.5;
53+
}
54+
55+
canvas#deck-canvas {
56+
mix-blend-mode: screen;
57+
}
58+
59+
#tooltip {
60+
width: auto;
61+
height: auto;
62+
display: none;
63+
position: absolute;
64+
font-size: 14px;
65+
border-radius: 5px;
66+
border: 1px solid #000;
67+
background-color: rgba(255, 255, 255, 0.75);
68+
padding: 0.6em;
69+
color: rgb(0, 0, 0);
70+
pointer-events: none;
71+
}
72+
</style>
73+
</head>
74+
<body>
75+
<div class="sidePanel">
76+
<fieldset style="width:320px;margin-bottom:10px;">
77+
<legend>Integrate with Flowmap.gl</legend>
78+
This sample shows a flow map on top of Azure Maps using the Flowmap.gl module.<br/>
79+
A flow map is useful for visualizing movement data between two geometry points.
80+
The data is displayed as arcs between the geometry points, and the thickness of the arcs represents the volume of movement (or any other meaningful information) between the points.<br/><br/>
81+
The sample uses data from BIXI, a public bike share system in Montreal. The flow map layer visualizes the movement of bikes between stations.
82+
Hover over the dots and arcs to see information about the locations and movements.<br/><br/>
83+
The code references Flowmap.gl's
84+
<a href="https://github.com/visgl/flowmap.gl/blob/main/examples/react-app" target="_blank">example</a>.
85+
</fieldset>
86+
87+
<table>
88+
<tr title="Dark Mode">
89+
<td>Dark Mode:</td>
90+
<td>
91+
<input type="checkbox" class="control" id="darkMode" checked title="Dark Mode" />
92+
</td>
93+
</tr>
94+
<tr title="Color Scheme">
95+
<td>Color Scheme:</td>
96+
<td>
97+
<select class="control" id="colorScheme" title="Color Scheme">
98+
<option>Blues</option>
99+
<option>Cool</option>
100+
<option>Peach</option>
101+
<option>Magenta</option>
102+
<option selected>Teal</option>
103+
</select>
104+
</td>
105+
</tr>
106+
<tr title="Clustering Enabled">
107+
<td>Clustering Enabled:</td>
108+
<td>
109+
<input type="checkbox" class="control" id="clusteringEnabled" checked title="Clustering Enabled" />
110+
</td>
111+
</tr>
112+
</table>
113+
</div>
114+
<div id="container">
115+
<div id="myMap"></div>
116+
<canvas id="deck-canvas"></canvas>
117+
<div id="tooltip"></div>
118+
</div>
119+
120+
</body>
121+
</html>

Samples/3D-layer/Flowmap.gl/build/index-6501962d.js

Lines changed: 2104 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "flowmap.gl-azuremaps-websdk-sample",
3+
"version": "0.0.2",
4+
"type": "module",
5+
"private": true,
6+
"license": "MIT",
7+
"scripts": {
8+
"dev": "vite",
9+
"build": "vite build",
10+
"preview": "vite preview"
11+
},
12+
"dependencies": {
13+
"@deck.gl/core": "^8.9.28",
14+
"@deck.gl/layers": "^8.9.28",
15+
"@flowmap.gl/data": "8.0.1",
16+
"@flowmap.gl/layers": "8.0.1",
17+
"azure-maps-control": "^3.4.0",
18+
"d3-fetch": "^3.0.1"
19+
},
20+
"devDependencies": {
21+
"vite": "^4.4.9"
22+
}
23+
}
21.5 KB
Loading
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
import {Deck} from "@deck.gl/core";
2+
import {FlowmapLayer, PickingType} from '@flowmap.gl/layers';
3+
import {getViewStateForLocations} from "@flowmap.gl/data";
4+
import {csv} from "d3-fetch";
5+
import atlas from "azure-maps-control";
6+
7+
let deck, locations, flows;
8+
let map;
9+
10+
function onload () {
11+
//Fetch the data.
12+
fetchData().then((data) => {
13+
//Retrieve the locations and flows from the data.
14+
({locations, flows} = data);
15+
const [width, height] = [globalThis.innerWidth, globalThis.innerHeight];
16+
const initialViewState = getViewStateForLocations(
17+
locations,
18+
(loc) => [loc.lon, loc.lat],
19+
[width, height],
20+
{pad: 0.3}
21+
);
22+
//Initialize a map instance.
23+
map = new atlas.Map("myMap", {
24+
style: 'grayscale_dark',
25+
interactive: false,
26+
//Deck.gl will be responsible for the interactivity of the map.
27+
center: [initialViewState.longitude, initialViewState.latitude],
28+
zoom: initialViewState.zoom,
29+
bearing: initialViewState.bearing,
30+
pitch: initialViewState.pitch,
31+
32+
//Add authentication details for connecting to Azure Maps.
33+
authOptions: {
34+
//Use Microsoft Entra ID authentication.
35+
authType: 'anonymous',
36+
clientId: 'e6b6ab59-eb5d-4d25-aa57-581135b927f0', //Your Azure Maps client id for accessing your Azure Maps account.
37+
getToken: function (resolve, reject, map) {
38+
//URL to your authentication service that retrieves an Microsoft Entra ID Token.
39+
var tokenServiceUrl = 'https://samples.azuremaps.com/api/GetAzureMapsToken';
40+
41+
fetch(tokenServiceUrl).then(r => r.text()).then(token => resolve(token));
42+
}
43+
44+
//Alternatively, use an Azure Maps key. Get an Azure Maps key at https://azure.com/maps. NOTE: The primary key should be used as the key.
45+
//authType: 'subscriptionKey',
46+
//subscriptionKey: '[YOUR_AZURE_MAPS_KEY]'
47+
}
48+
});
49+
50+
//Add a style control to the map.
51+
map.events.add("ready", () => {
52+
map.controls.add(new atlas.control.StyleControl({
53+
mapStyles: ['road', 'grayscale_light', 'grayscale_dark', 'night', 'satellite'],
54+
}), {
55+
position: "top-right",
56+
});
57+
});
58+
59+
//Initialize a deck.gl instance.
60+
deck = new Deck({
61+
canvas: "deck-canvas",
62+
width: "100%",
63+
height: "100%",
64+
initialViewState: initialViewState,
65+
controller: true,
66+
map: true,
67+
68+
//Update the map view state when the deck.gl view state changes.
69+
onViewStateChange: ({viewState}) => {
70+
map.setCamera({
71+
center: [viewState.longitude, viewState.latitude],
72+
zoom: viewState.zoom,
73+
bearing: viewState.bearing,
74+
pitch: viewState.pitch,
75+
});
76+
},
77+
layers: [],
78+
});
79+
80+
//Add the flowmap layer to the deck.gl instance.
81+
addLayer();
82+
83+
//Add event listeners to the controls on the side panel.
84+
document.querySelectorAll(".control").forEach((control) => {
85+
control.onchange = addLayer;
86+
});
87+
document.getElementById("darkMode").onchange = onDarkModeChange;
88+
89+
//Move the canvas under the map controls for better accessibility.
90+
const flowmap = document.getElementById("deck-canvas");
91+
const mapContainer = document.getElementById("myMap");
92+
mapContainer.insertBefore(flowmap, mapContainer.querySelector(".atlas-control-container"));
93+
});
94+
}
95+
96+
async function fetchData() {
97+
const [locations, flows] = await Promise.all([
98+
csv('/data/flowmap/locations.csv', (row) => ({
99+
id: row.id,
100+
name: row.name,
101+
lat: +row.lat,
102+
lon: +row.lon,
103+
})),
104+
csv('/data/flowmap/flows.csv', (row) => ({
105+
origin: row.origin,
106+
dest: row.dest,
107+
count: +row.count,
108+
})),
109+
]);
110+
return { locations, flows };
111+
}
112+
113+
function addLayer() {
114+
//Set up the flowmap layer whenever the selected options change.
115+
deck.setProps({
116+
layers: [
117+
new FlowmapLayer({
118+
id: "my-flowmap-layer",
119+
data: {locations, flows},
120+
pickable: true,
121+
darkMode: getIsChecked("darkMode"),
122+
colorScheme: getSelectValue("colorScheme"),
123+
clusteringEnabled: getIsChecked("clusteringEnabled"),
124+
getLocationId: (loc) => loc.id,
125+
getLocationLat: (loc) => loc.lat,
126+
getLocationLon: (loc) => loc.lon,
127+
getFlowOriginId: (flow) => flow.origin,
128+
getFlowDestId: (flow) => flow.dest,
129+
getFlowMagnitude: (flow) => flow.count,
130+
getLocationName: (loc) => loc.name,
131+
onHover: (info) => updateTooltip(getTooltipState(info)),
132+
}),
133+
],
134+
});
135+
}
136+
137+
function onDarkModeChange() {
138+
//Update the map style for better visibility in different modes.
139+
map.setStyle({style: getIsChecked("darkMode") ? "grayscale_dark" : "grayscale_light"});
140+
document.getElementById("deck-canvas").style.mixBlendMode = getIsChecked("darkMode") ? "screen" : "darken";
141+
document.getElementById("container").style.backgroundColor = getIsChecked("darkMode") ? "#000" : "#fff";
142+
addLayer();
143+
}
144+
145+
function updateTooltip(state) {
146+
const tooltip = document.getElementById("tooltip");
147+
if (!state) {
148+
tooltip.style.display = "none";
149+
return;
150+
}
151+
tooltip.style.left = `${state.position.left}px`;
152+
tooltip.style.top = `${state.position.top}px`
153+
tooltip.innerHTML = state.content;
154+
tooltip.style.display = "block";
155+
}
156+
157+
//Generate the postion and content of the tooltip.
158+
function getTooltipState(info) {
159+
if (!info) return undefined;
160+
161+
const {x, y, object} = info;
162+
const position = {left: x, top: y};
163+
switch (object?.type) {
164+
case PickingType.LOCATION:
165+
const nameElm = document.createElement("b");
166+
nameElm.innerText = object.name.replaceAll("\"", "");
167+
const incomingElm = document.createElement("li");
168+
incomingElm.innerText = `Incoming trips: ${object.totals.incomingCount}`;
169+
const outgoingElm = document.createElement("li");
170+
outgoingElm.innerText = `Outgoing trips: ${object.totals.outgoingCount}`;
171+
const internalElm = document.createElement("li");
172+
internalElm.innerText = `Internal or round trips: ${object.totals.internalCount}`;
173+
return {
174+
position,
175+
content: [nameElm, incomingElm, outgoingElm, internalElm].map((elm) => elm.outerHTML).join(""),
176+
};
177+
case PickingType.FLOW:
178+
const titleElm = document.createElement("b");
179+
titleElm.innerText = "Route Info";
180+
const routeElm = document.createElement("li");
181+
routeElm.innerText = `Bike Station: ${object.origin.id.slice(2, -2)}${object.dest.id.slice(2, -2)}`;
182+
const countElm = document.createElement("li");
183+
countElm.innerText = `Trips Count: ${object.count}`;
184+
return {
185+
position,
186+
content: [titleElm, routeElm, countElm].map((elm) => elm.outerHTML).join(""),
187+
};
188+
}
189+
return undefined;
190+
}
191+
192+
function getSelectValue(id) {
193+
var elm = document.getElementById(id);
194+
return elm.options[elm.selectedIndex].value;
195+
}
196+
function getIsChecked(id) {
197+
return document.getElementById(id).checked;
198+
}
199+
200+
//Initialize when the page loads.
201+
document.body.onload = onload;

0 commit comments

Comments
 (0)