@itwin/geonames-extension
Version:
Geolocation Extension
191 lines • 10.1 kB
JavaScript
;
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.GeoNameExtension = exports.GeoNameMarkerManager = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const core_frontend_1 = require("@itwin/core-frontend");
const core_geometry_1 = require("@itwin/core-geometry");
/** Marker positioned where there is a geographic entity. */
class GeoNameMarker extends core_frontend_1.Marker {
constructor(location, props, icon) {
super(location, GeoNameMarker._size);
this.props = props;
this.setImage(icon); // save icon
this.imageSize = GeoNameMarker._imageSize; // 40x40
// set the tooltip when promise resolves. We won't need it for a while anyway.
this.setScaleFactor({ low: 1, high: 1 }); // no size dependence for now.
this.labelOffset = { x: 0, y: -24 };
this.title = props.name;
if (props.population)
this.title = `${this.title} (${core_frontend_1.IModelApp.localization.getLocalizedString("geoNames:misc.Population")}: ${props.population})`;
// it would be better to use "this.label" here for a pure text string. We'll do it this way just to show that you can use HTML too
// this.htmlElement = document.createElement("div");
// this.htmlElement.innerHTML = props.name; // put the name of the location.
this.label = props.name;
}
onMouseButton(ev) {
if (core_frontend_1.InputSource.Mouse === ev.inputSource && ev.isDown && ev.viewport !== undefined && ev.viewport.view instanceof core_frontend_1.ViewState3d) {
if (core_frontend_1.BeButton.Data === ev.button) {
const evViewport = ev.viewport;
(async () => {
await evViewport.animateFlyoverToGlobalLocation({ center: core_common_1.Cartographic.fromRadians({ longitude: this.props.lng * core_geometry_1.Angle.radiansPerDegree, latitude: this.props.lat * core_geometry_1.Angle.radiansPerDegree }) });
})().catch(() => { });
}
else if (core_frontend_1.BeButton.Reset === ev.button && undefined !== this.props.wikipedia && 0 !== this.props.wikipedia.length)
window.open(`https://${this.props.wikipedia}`);
}
return true;
}
}
GeoNameMarker._size = core_geometry_1.Point2d.create(20, 20);
GeoNameMarker._imageSize = core_geometry_1.Point2d.create(30, 30);
class GeoNameMarkerSet extends core_frontend_1.MarkerSet {
constructor() {
super(...arguments);
this.minimumClusterSize = 5;
}
getClusterMarker(cluster) { return new core_frontend_1.Marker(cluster.getClusterLocation(), cluster.markers[0].size); }
}
class GeoNameMarkerManager {
constructor(vp, _cityMarkerImage, _cityCount = 50) {
this._cityMarkerImage = _cityMarkerImage;
this._cityCount = _cityCount;
this._markerSet = new GeoNameMarkerSet(vp);
}
decorate(context) {
if (this._markerSet !== undefined)
this._markerSet.addDecoration(context);
}
synch(viewport) {
const currentViewport = this._markerSet.viewport;
if (currentViewport !== viewport)
this._markerSet.changeViewport(viewport);
const view = viewport.view;
const worldFrust = viewport.getFrustum();
const longLatRange = core_geometry_1.Range2d.createNull();
for (const corner of worldFrust.points) {
const carto = view.rootToCartographic(corner);
if (undefined !== carto)
longLatRange.extendXY(carto.longitude, carto.latitude);
}
this.doCitySearch(longLatRange, this._cityCount).then((cities) => {
if (cities !== undefined) {
for (const city of cities) {
GeoNameMarkerManager._scratchCarto.longitude = city.lng * core_geometry_1.Angle.radiansPerDegree;
GeoNameMarkerManager._scratchCarto.latitude = city.lat * core_geometry_1.Angle.radiansPerDegree;
this._markerSet.markers.add(new GeoNameMarker(view.cartographicToRoot(GeoNameMarkerManager._scratchCarto, GeoNameMarkerManager._scratchPoint), city, this._cityMarkerImage));
}
this._markerSet.markDirty();
core_frontend_1.IModelApp.viewManager.invalidateDecorationsAllViews();
core_frontend_1.IModelApp.requestNextAnimation();
}
}).catch(() => { });
}
// Load one image, logging if there was an error
static async loadImage(src) {
try {
return await (0, core_frontend_1.imageElementFromUrl)(src); // note: "return await" is necessary inside try/catch
}
catch (err) {
core_bentley_1.Logger.logError("SectionLocationSetDecoration", `Could not load image ${src}`);
}
return undefined;
}
outputInfoMessage(messageKey) {
const message = core_frontend_1.IModelApp.localization.getLocalizedString(`geoNames:messages.${messageKey}`);
const msgDetails = new core_frontend_1.NotifyMessageDetails(core_frontend_1.OutputMessagePriority.Info, message);
core_frontend_1.IModelApp.notifications.outputMessage(msgDetails);
}
radiansToString(radians) { return (radians * core_geometry_1.Angle.degreesPerRadian).toFixed(5); }
async doCitySearch(longLatRange, cityCount) {
const urlTemplate = "http://api.geonames.org/citiesJSON?&north={north}&south={south}&east={east}&west={west}&lang=en&username=BentleySystems&maxRows={count}";
const url = urlTemplate.replace("{west}", this.radiansToString(longLatRange.low.x)).replace("{south}", this.radiansToString(longLatRange.low.y)).replace("{east}", this.radiansToString(longLatRange.high.x)).replace("{north}", this.radiansToString(longLatRange.high.y)).replace("{count}", cityCount.toString());
try {
this.outputInfoMessage("LoadingLocations");
let json = await fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json", // eslint-disable-line @typescript-eslint/naming-convention
},
});
json = json.json();
const cities = new Array();
for (const geoName of json.geonames) {
cities.push(geoName);
}
this.outputInfoMessage("LoadingComplete");
return cities;
}
catch (error) {
return undefined;
}
}
/** Start showing markers if not currently active (or optionally refresh when currently displayed). */
static async show(vp) {
if (undefined === GeoNameMarkerManager.decorator) {
const cityMarkerImage = await this.loadImage("./city.ico");
if (undefined === cityMarkerImage)
return; // No point continuing if we don't have a marker image to show...
GeoNameMarkerManager.decorator = new GeoNameMarkerManager(vp, cityMarkerImage);
core_frontend_1.IModelApp.viewManager.addDecorator(GeoNameMarkerManager.decorator);
}
GeoNameMarkerManager.decorator.synch(vp);
}
static clear(_vp) {
if (undefined !== GeoNameMarkerManager.decorator) {
core_frontend_1.IModelApp.viewManager.dropDecorator(GeoNameMarkerManager.decorator);
GeoNameMarkerManager.decorator = undefined;
}
}
static update(vp) {
if (undefined !== GeoNameMarkerManager.decorator) {
GeoNameMarkerManager.decorator.synch(vp);
}
}
}
exports.GeoNameMarkerManager = GeoNameMarkerManager;
GeoNameMarkerManager._scratchCarto = core_common_1.Cartographic.createZero();
GeoNameMarkerManager._scratchPoint = core_geometry_1.Point3d.createZero();
/** An Immediate Tool that attempts to use the geoLocation API to find the given feature */
class GeoNameTool extends core_frontend_1.Tool {
static get maxArgs() { return 1; }
static get minArgs() { return 0; }
async run(viewport) {
if (undefined === viewport)
viewport = core_frontend_1.IModelApp.viewManager.selectedView;
if (undefined !== viewport)
this.doRunWithViewport(viewport);
return true;
}
}
class GeoNameOnTool extends GeoNameTool {
doRunWithViewport(vp) {
GeoNameMarkerManager.show(vp).then(() => { }).catch(() => { });
}
}
GeoNameOnTool.toolId = "GeoNamesOnTool";
class GeoNameOffTool extends GeoNameTool {
doRunWithViewport(vp) { GeoNameMarkerManager.clear(vp); }
}
GeoNameOffTool.toolId = "GeoNamesOffTool";
class GeoNameUpdateTool extends GeoNameTool {
doRunWithViewport(vp) { GeoNameMarkerManager.update(vp); }
}
GeoNameUpdateTool.toolId = "GeoNamesUpdateTool";
class GeoNameExtension {
static async initialize() {
await core_frontend_1.IModelApp.localization.registerNamespace(this._defaultNs);
core_frontend_1.IModelApp.tools.register(GeoNameOnTool, this._defaultNs);
core_frontend_1.IModelApp.tools.register(GeoNameOffTool, this._defaultNs);
core_frontend_1.IModelApp.tools.register(GeoNameUpdateTool, this._defaultNs);
if (undefined !== core_frontend_1.IModelApp.viewManager.selectedView)
await GeoNameMarkerManager.show(core_frontend_1.IModelApp.viewManager.selectedView);
}
}
exports.GeoNameExtension = GeoNameExtension;
GeoNameExtension._defaultNs = "geoNames";
//# sourceMappingURL=geoNames.js.map