This repository has been archived by the owner on Mar 8, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 197
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MINOR: Add dynamic markers example. (#1997)
* MINOR: Add dynamic markers example. * MINOR: Rename example.
- Loading branch information
1 parent
7624c25
commit f729dac
Showing
1 changed file
with
192 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
/* | ||
* Copyright (C) 2017-2020 HERE Europe B.V. | ||
* Licensed under Apache 2.0, see full license in LICENSE | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { FeaturesDataSource, MapViewPointFeature } from "@here/harp-features-datasource"; | ||
import { GeoCoordinates } from "@here/harp-geoutils"; | ||
import { MapControls, MapControlsUI } from "@here/harp-map-controls"; | ||
import { CopyrightElementHandler, MapView } from "@here/harp-mapview"; | ||
import { | ||
APIFormat, | ||
AuthenticationMethod, | ||
GeoJsonDataProvider, | ||
VectorTileDataSource | ||
} from "@here/harp-vectortile-datasource"; | ||
|
||
import { apikey, copyrightInfo } from "../config"; | ||
|
||
/** | ||
* This examples shows how to render dynamically generated GeoJSON points as markers with picking | ||
* support. | ||
*/ | ||
export namespace DynamicMarkersExample { | ||
const icons = [ | ||
{ | ||
name: "redIcon", | ||
url: | ||
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzOCIgaGVpZ2h0PSI0NyIgdmlld0JveD0iMCAwIDM4IDQ3Ij48ZyBmaWxsPSJub25lIj48cGF0aCBmaWxsPSIjMEYxNjIxIiBmaWxsLW9wYWNpdHk9Ii40IiBkPSJNMTUgNDZjMCAuMzE3IDEuNzkuNTc0IDQgLjU3NHM0LS4yNTcgNC0uNTc0YzAtLjMxNy0xLjc5LS41NzQtNC0uNTc0cy00IC4yNTctNCAuNTc0eiI+PC9wYXRoPjxwYXRoIGZpbGw9IiNiNjAxMDEiIGQ9Ik0zMy4yNSAzMS42NTJBMTkuMDE1IDE5LjAxNSAwIDAgMCAzOCAxOS4wNkMzOCA4LjU0OSAyOS40NzggMCAxOSAwUzAgOC41NSAwIDE5LjA1OWMwIDQuODIzIDEuNzk1IDkuMjMzIDQuNzUgMTIuNTkzTDE4Ljk3NSA0NiAzMy4yNSAzMS42NTJ6Ij48L3BhdGg+PHBhdGggZmlsbD0iIzZBNkQ3NCIgZmlsbC1vcGFjaXR5PSIuNSIgZD0iTTI2Ljg2MiAzNy41bDQuNzE0LTQuNzdjMy44MjItMy41NzYgNS45MjQtOC40MTEgNS45MjQtMTMuNjJDMzcuNSA4Ljg0NyAyOS4yLjUgMTkgLjVTLjUgOC44NDguNSAxOS4xMWMwIDUuMjA5IDIuMTAyIDEwLjA0NCA1LjkxOSAxMy42MTRsNC43MTkgNC43NzZoMTUuNzI0ek0xOSAwYzEwLjQ5MyAwIDE5IDguNTI1IDE5IDE5LjA0MSAwIDUuNTA3LTIuMzQ4IDEwLjQ1NC02LjA3OSAxMy45MzJMMTkgNDYgNi4wNzkgMzIuOTczQzIuMzQ4IDI5LjQ5NSAwIDI0LjU0OCAwIDE5LjA0IDAgOC41MjUgOC41MDcgMCAxOSAweiI+PC9wYXRoPjwvZz48L3N2Zz4K" | ||
}, | ||
{ | ||
name: "greenIcon", | ||
url: | ||
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzOCIgaGVpZ2h0PSI0NyIgdmlld0JveD0iMCAwIDM4IDQ3Ij48ZyBmaWxsPSJub25lIj48cGF0aCBmaWxsPSIjMEYxNjIxIiBmaWxsLW9wYWNpdHk9Ii40IiBkPSJNMTUgNDZjMCAuMzE3IDEuNzkuNTc0IDQgLjU3NHM0LS4yNTcgNC0uNTc0YzAtLjMxNy0xLjc5LS41NzQtNC0uNTc0cy00IC4yNTctNCAuNTc0eiI+PC9wYXRoPjxwYXRoIGZpbGw9IiMwNGI2MDEiIGQ9Ik0zMy4yNSAzMS42NTJBMTkuMDE1IDE5LjAxNSAwIDAgMCAzOCAxOS4wNkMzOCA4LjU0OSAyOS40NzggMCAxOSAwUzAgOC41NSAwIDE5LjA1OWMwIDQuODIzIDEuNzk1IDkuMjMzIDQuNzUgMTIuNTkzTDE4Ljk3NSA0NiAzMy4yNSAzMS42NTJ6Ij48L3BhdGg+PHBhdGggZmlsbD0iIzZBNkQ3NCIgZmlsbC1vcGFjaXR5PSIuNSIgZD0iTTI2Ljg2MiAzNy41bDQuNzE0LTQuNzdjMy44MjItMy41NzYgNS45MjQtOC40MTEgNS45MjQtMTMuNjJDMzcuNSA4Ljg0NyAyOS4yLjUgMTkgLjVTLjUgOC44NDguNSAxOS4xMWMwIDUuMjA5IDIuMTAyIDEwLjA0NCA1LjkxOSAxMy42MTRsNC43MTkgNC43NzZoMTUuNzI0ek0xOSAwYzEwLjQ5MyAwIDE5IDguNTI1IDE5IDE5LjA0MSAwIDUuNTA3LTIuMzQ4IDEwLjQ1NC02LjA3OSAxMy45MzJMMTkgNDYgNi4wNzkgMzIuOTczQzIuMzQ4IDI5LjQ5NSAwIDI0LjU0OCAwIDE5LjA0IDAgOC41MjUgOC41MDcgMCAxOSAweiI+PC9wYXRoPjwvZz48L3N2Zz4K" | ||
}, | ||
{ | ||
name: "blueIcon", | ||
url: | ||
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzOCIgaGVpZ2h0PSI0NyIgdmlld0JveD0iMCAwIDM4IDQ3Ij48ZyBmaWxsPSJub25lIj48cGF0aCBmaWxsPSIjMEYxNjIxIiBmaWxsLW9wYWNpdHk9Ii40IiBkPSJNMTUgNDZjMCAuMzE3IDEuNzkuNTc0IDQgLjU3NHM0LS4yNTcgNC0uNTc0YzAtLjMxNy0xLjc5LS41NzQtNC0uNTc0cy00IC4yNTctNCAuNTc0eiI+PC9wYXRoPjxwYXRoIGZpbGw9IiMwMTgwYjYiIGQ9Ik0zMy4yNSAzMS42NTJBMTkuMDE1IDE5LjAxNSAwIDAgMCAzOCAxOS4wNkMzOCA4LjU0OSAyOS40NzggMCAxOSAwUzAgOC41NSAwIDE5LjA1OWMwIDQuODIzIDEuNzk1IDkuMjMzIDQuNzUgMTIuNTkzTDE4Ljk3NSA0NiAzMy4yNSAzMS42NTJ6Ij48L3BhdGg+PHBhdGggZmlsbD0iIzZBNkQ3NCIgZmlsbC1vcGFjaXR5PSIuNSIgZD0iTTI2Ljg2MiAzNy41bDQuNzE0LTQuNzdjMy44MjItMy41NzYgNS45MjQtOC40MTEgNS45MjQtMTMuNjJDMzcuNSA4Ljg0NyAyOS4yLjUgMTkgLjVTLjUgOC44NDguNSAxOS4xMWMwIDUuMjA5IDIuMTAyIDEwLjA0NCA1LjkxOSAxMy42MTRsNC43MTkgNC43NzZoMTUuNzI0ek0xOSAwYzEwLjQ5MyAwIDE5IDguNTI1IDE5IDE5LjA0MSAwIDUuNTA3LTIuMzQ4IDEwLjQ1NC02LjA3OSAxMy45MzJMMTkgNDYgNi4wNzkgMzIuOTczQzIuMzQ4IDI5LjQ5NSAwIDI0LjU0OCAwIDE5LjA0IDAgOC41MjUgOC41MDcgMCAxOSAweiI+PC9wYXRoPjwvZz48L3N2Zz4K" | ||
} | ||
]; | ||
|
||
/** | ||
* Creates a new MapView for the HTMLCanvasElement of the given id. | ||
*/ | ||
function initializeMapView(id: string): MapView { | ||
const canvas = document.getElementById(id) as HTMLCanvasElement; | ||
const map = new MapView({ | ||
canvas, | ||
theme: { | ||
extends: "resources/berlin_tilezen_base.json", | ||
styles: { | ||
// Specify the styling for the markers. | ||
geojson: [ | ||
{ | ||
when: ["==", ["geometry-type"], "Point"], | ||
technique: "labeled-icon", | ||
imageTexture: ["get", "icon"], | ||
text: ["get", "text"], | ||
size: 15, | ||
priority: 1000, | ||
color: "black", | ||
iconMayOverlap: true, | ||
textMayOverlap: true, | ||
renderOrder: ["get", "renderOrder"], | ||
iconFadeTime: 0, | ||
textFadeTime: 0 | ||
} | ||
] | ||
} | ||
}, | ||
target: new GeoCoordinates(52.52, 13.4), | ||
zoomLevel: 12 | ||
}); | ||
|
||
CopyrightElementHandler.install("copyrightNotice").attach(map); | ||
|
||
const controls = new MapControls(map); | ||
|
||
// Add an UI. | ||
const ui = new MapControlsUI(controls, { projectionSwitch: true, zoomLevel: "input" }); | ||
canvas.parentElement!.appendChild(ui.domElement); | ||
|
||
window.addEventListener("resize", () => { | ||
map.resize(window.innerWidth, window.innerHeight); | ||
}); | ||
|
||
map.update(); | ||
|
||
return map; | ||
} | ||
|
||
function handlePick( | ||
mapView: MapView, | ||
markersDataSource: FeaturesDataSource, | ||
x: number, | ||
y: number | ||
): void { | ||
// Intersection test filtering the results by layer name to get only markers. | ||
const layerName = (markersDataSource.dataProvider() as GeoJsonDataProvider).name; | ||
const results = mapView.intersectMapObjects(x, y).filter(result => { | ||
return result.userData?.$layer === layerName; | ||
}); | ||
|
||
if (results.length === 0) { | ||
return; | ||
} | ||
|
||
const uuid = results[0].userData?.__mapViewUuid; | ||
if (uuid !== undefined) { | ||
const feature = new MapViewPointFeature([]); | ||
feature.uuid = uuid; | ||
markersDataSource.remove(feature); | ||
} | ||
} | ||
|
||
let markerId = 0; | ||
function attachClickEvents(mapView: MapView, markersDataSource: FeaturesDataSource) { | ||
mapView.canvas.addEventListener("click", event => { | ||
if (event.shiftKey) { | ||
const geo = mapView.getGeoCoordinatesAt(event.clientX, event.clientY); | ||
if (geo) { | ||
// Add a new marker to the data source at the click coordinates. | ||
markersDataSource.add( | ||
new MapViewPointFeature(geo.toGeoPoint() as number[], { | ||
text: markerId.toString(), | ||
id: markerId, | ||
icon: icons[markerId % icons.length].name, | ||
renderOrder: markerId | ||
}) | ||
); | ||
markerId++; | ||
} | ||
} else if (event.ctrlKey) { | ||
handlePick(mapView, markersDataSource, event.pageX, event.pageY); | ||
} | ||
}); | ||
|
||
window.addEventListener("keypress", event => { | ||
if (event.key === "c") { | ||
markersDataSource.clear(); | ||
markerId = 0; | ||
} | ||
}); | ||
|
||
const instructions = ` | ||
Shift+Left Click to add a marker<br/>Ctrl+Left Click to remove it<br/> | ||
Press 'c' to clear the map.<br/>`; | ||
const message = document.createElement("div"); | ||
message.style.position = "absolute"; | ||
message.style.cssFloat = "right"; | ||
message.style.top = "10px"; | ||
message.style.right = "10px"; | ||
message.style.backgroundColor = "grey"; | ||
message.innerHTML = instructions; | ||
document.body.appendChild(message); | ||
} | ||
|
||
function attachDataSources(mapView: MapView) { | ||
const omvDataSource = new VectorTileDataSource({ | ||
baseUrl: "https://vector.hereapi.com/v2/vectortiles/base/mc", | ||
apiFormat: APIFormat.XYZOMV, | ||
styleSetName: "tilezen", | ||
maxDataLevel: 17, | ||
authenticationCode: apikey, | ||
authenticationMethod: { | ||
method: AuthenticationMethod.QueryString, | ||
name: "apikey" | ||
}, | ||
copyrightInfo | ||
}); | ||
mapView.addDataSource(omvDataSource); | ||
|
||
// Register the icon image referenced in the style. | ||
for (const { name, url } of icons) { | ||
mapView.userImageCache.addImage(name, url); | ||
} | ||
|
||
// Create a [[FeaturesDataSource]] for the markers. | ||
const markersDataSource = new FeaturesDataSource({ | ||
name: "geojson", | ||
styleSetName: "geojson", | ||
gatherFeatureAttributes: true | ||
}); | ||
mapView.addDataSource(markersDataSource); | ||
|
||
attachClickEvents(mapView, markersDataSource); | ||
} | ||
|
||
const mapView = initializeMapView("mapCanvas"); | ||
attachDataSources(mapView); | ||
} |