mirror of
https://github.com/FlipsideCrypto/DefinitelyTyped.git
synced 2026-02-06 10:56:53 +00:00
457 lines
12 KiB
TypeScript
457 lines
12 KiB
TypeScript
import { Collection, Map, MapBrowserEvent, Overlay, PluggableMap, View } from 'ol';
|
|
import { unByKey } from 'ol/Observable';
|
|
import { stableSort } from 'ol/array';
|
|
import {
|
|
Control,
|
|
FullScreen,
|
|
MousePosition,
|
|
OverviewMap,
|
|
ScaleLine,
|
|
ZoomSlider,
|
|
ZoomToExtent,
|
|
defaults as defaultControls,
|
|
} from 'ol/control';
|
|
import { Options as ControlOptions } from 'ol/control/Control';
|
|
import { toStringXY } from 'ol/coordinate';
|
|
import { EventsKey } from 'ol/events';
|
|
import { applyTransform } from 'ol/extent';
|
|
import { GeoJSON, MVT } from 'ol/format';
|
|
import GeometryType from 'ol/geom/GeometryType';
|
|
import { Draw, Modify, Select, defaults as defaultInteractions } from 'ol/interaction';
|
|
import { Tile as TileLayer, Vector as VectorLayer, VectorTile as VectorTileLayer } from 'ol/layer';
|
|
import { fromLonLat, get as getProjection, getTransform } from 'ol/proj';
|
|
import { register } from 'ol/proj/proj4';
|
|
import { OSM, Vector as VectorSource, VectorTile as VectorTileSource } from 'ol/source';
|
|
import { Circle, Fill, Stroke, Style } from 'ol/style';
|
|
import { StyleFunction } from 'ol/style/Style';
|
|
|
|
import proj4 = require('proj4');
|
|
|
|
/**
|
|
* ==================================================
|
|
* # Styles
|
|
* ==================================================
|
|
*/
|
|
|
|
const image = new Circle({
|
|
radius: 5,
|
|
fill: null as any,
|
|
stroke: new Stroke({ color: 'red', width: 1 }),
|
|
});
|
|
|
|
const styles: { [key: string]: Style } = {
|
|
Point: new Style({
|
|
image,
|
|
}),
|
|
LineString: new Style({
|
|
stroke: new Stroke({
|
|
color: 'green',
|
|
width: 1,
|
|
}),
|
|
}),
|
|
MultiLineString: new Style({
|
|
stroke: new Stroke({
|
|
color: 'green',
|
|
width: 1,
|
|
}),
|
|
}),
|
|
MultiPoint: new Style({
|
|
image,
|
|
}),
|
|
MultiPolygon: new Style({
|
|
stroke: new Stroke({
|
|
color: 'yellow',
|
|
width: 1,
|
|
}),
|
|
fill: new Fill({
|
|
color: 'rgba(255, 255, 0, 0.1)',
|
|
}),
|
|
}),
|
|
Polygon: new Style({
|
|
stroke: new Stroke({
|
|
color: 'blue',
|
|
lineDash: [4],
|
|
width: 3,
|
|
}),
|
|
fill: new Fill({
|
|
color: 'rgba(0, 0, 255, 0.1)',
|
|
}),
|
|
}),
|
|
GeometryCollection: new Style({
|
|
stroke: new Stroke({
|
|
color: 'magenta',
|
|
width: 2,
|
|
}),
|
|
fill: new Fill({
|
|
color: 'magenta',
|
|
}),
|
|
image: new Circle({
|
|
radius: 10,
|
|
fill: null as any,
|
|
stroke: new Stroke({
|
|
color: 'magenta',
|
|
}),
|
|
}),
|
|
}),
|
|
Circle: new Style({
|
|
stroke: new Stroke({
|
|
color: 'red',
|
|
width: 2,
|
|
}),
|
|
fill: new Fill({
|
|
color: 'rgba(255,0,0,0.2)',
|
|
}),
|
|
}),
|
|
};
|
|
|
|
const styleFunction: StyleFunction = feature => styles[feature.getGeometry().getType()];
|
|
|
|
/**
|
|
* ==================================================
|
|
* # Vector
|
|
* ==================================================
|
|
*/
|
|
|
|
const geojsonObj = {
|
|
type: 'FeatureCollection',
|
|
crs: { type: 'name', properties: { name: 'EPSG:3857' } },
|
|
features: [
|
|
{ type: 'Feature', geometry: { type: 'Point', coordinates: [0, 0] } },
|
|
{
|
|
type: 'Feature',
|
|
geometry: {
|
|
type: 'LineString',
|
|
coordinates: [
|
|
[4000000, -2000000],
|
|
[8000000, 2000000],
|
|
],
|
|
},
|
|
},
|
|
{
|
|
type: 'Feature',
|
|
geometry: {
|
|
type: 'LineString',
|
|
coordinates: [
|
|
[4000000, 2000000],
|
|
[8000000, -2000000],
|
|
],
|
|
},
|
|
},
|
|
{
|
|
type: 'Feature',
|
|
geometry: {
|
|
type: 'Polygon',
|
|
coordinates: [
|
|
[
|
|
[-5000000, -1000000],
|
|
[-4000000, 1000000],
|
|
[-3000000, -1000000],
|
|
],
|
|
],
|
|
},
|
|
},
|
|
{
|
|
type: 'Feature',
|
|
geometry: {
|
|
type: 'MultiLineString',
|
|
coordinates: [
|
|
[
|
|
[-1000000, -750000],
|
|
[-1000000, 750000],
|
|
],
|
|
[
|
|
[1000000, -750000],
|
|
[1000000, 750000],
|
|
],
|
|
[
|
|
[-750000, -1000000],
|
|
[750000, -1000000],
|
|
],
|
|
[
|
|
[-750000, 1000000],
|
|
[750000, 1000000],
|
|
],
|
|
],
|
|
},
|
|
},
|
|
{
|
|
type: 'Feature',
|
|
geometry: {
|
|
type: 'MultiPolygon',
|
|
coordinates: [
|
|
[
|
|
[
|
|
[-5000000, 6000000],
|
|
[-5000000, 8000000],
|
|
[-3000000, 8000000],
|
|
[-3000000, 6000000],
|
|
],
|
|
],
|
|
[
|
|
[
|
|
[-2000000, 6000000],
|
|
[-2000000, 8000000],
|
|
[0, 8000000],
|
|
[0, 6000000],
|
|
],
|
|
],
|
|
[
|
|
[
|
|
[1000000, 6000000],
|
|
[1000000, 8000000],
|
|
[3000000, 8000000],
|
|
[3000000, 6000000],
|
|
],
|
|
],
|
|
],
|
|
},
|
|
},
|
|
{
|
|
type: 'Feature',
|
|
geometry: {
|
|
type: 'GeometryCollection',
|
|
geometries: [
|
|
{
|
|
type: 'LineString',
|
|
coordinates: [
|
|
[-5000000, -5000000],
|
|
[0, -5000000],
|
|
],
|
|
},
|
|
{ type: 'Point', coordinates: [4000000, -5000000] },
|
|
{
|
|
type: 'Polygon',
|
|
coordinates: [
|
|
[
|
|
[1000000, -6000000],
|
|
[2000000, -4000000],
|
|
[3000000, -6000000],
|
|
],
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
const vectorSource = new VectorSource({
|
|
features: new GeoJSON().readFeatures(geojsonObj),
|
|
});
|
|
|
|
const vectorLayer = new VectorLayer({
|
|
source: vectorSource,
|
|
style: styleFunction,
|
|
visible: true,
|
|
zIndex: 10,
|
|
});
|
|
|
|
const vectorTileSource = new VectorTileSource({
|
|
format: new MVT(),
|
|
url: 'https://basemaps.arcgis.com/v1/arcgis/rest/services/World_Basemap/VectorTileServer/tile/{z}/{y}/{x}.pbf',
|
|
});
|
|
|
|
const vectorTileLayer = new VectorTileLayer({
|
|
source: vectorTileSource,
|
|
visible: false,
|
|
zIndex: 9,
|
|
});
|
|
|
|
/**
|
|
* ==================================================
|
|
* # Tile
|
|
* ==================================================
|
|
*/
|
|
|
|
const osmLayer = new TileLayer({
|
|
source: new OSM({
|
|
crossOrigin: 'anonymous',
|
|
}),
|
|
visible: true,
|
|
zIndex: 0,
|
|
});
|
|
|
|
/**
|
|
* ==================================================
|
|
* # Controls
|
|
* ==================================================
|
|
*/
|
|
|
|
const layers = [osmLayer, vectorLayer, vectorTileLayer];
|
|
|
|
const controls = defaultControls().extend([
|
|
new FullScreen(),
|
|
new MousePosition({
|
|
coordinateFormat: coord => toStringXY(coord!, 8),
|
|
undefinedHTML: '',
|
|
}),
|
|
new OverviewMap({
|
|
layers,
|
|
view: new View({
|
|
projection: 'EPSG:3857',
|
|
}),
|
|
}),
|
|
new ScaleLine(),
|
|
new ZoomSlider(),
|
|
new ZoomToExtent(),
|
|
]);
|
|
|
|
/**
|
|
* ==================================================
|
|
* # Interactions
|
|
* ==================================================
|
|
*/
|
|
|
|
const drawInteractions: Draw[] = [];
|
|
(Object.keys(GeometryType) as (keyof typeof GeometryType)[]).forEach(type => {
|
|
const draw = new Draw({
|
|
type: GeometryType[type],
|
|
});
|
|
|
|
drawInteractions.push(draw);
|
|
});
|
|
|
|
const selectInteraction = new Select({
|
|
features: new Collection(vectorSource.getFeatures()),
|
|
});
|
|
|
|
const modifyInteraction = new Modify({
|
|
features: selectInteraction.getFeatures(),
|
|
});
|
|
|
|
const interactions = defaultInteractions().extend([selectInteraction, modifyInteraction]);
|
|
|
|
/**
|
|
* ==================================================
|
|
* # Map and View
|
|
* ==================================================
|
|
*/
|
|
|
|
const view = new View({
|
|
center: [0, 0],
|
|
projection: 'EPSG:3857',
|
|
zoom: 10,
|
|
});
|
|
|
|
const map = new Map({
|
|
target: 'map',
|
|
view,
|
|
layers,
|
|
controls,
|
|
interactions,
|
|
});
|
|
|
|
/**
|
|
* ==================================================
|
|
* # Reprojection
|
|
* ==================================================
|
|
*/
|
|
|
|
const projSpec = {
|
|
code: 'EPSG:4813',
|
|
bbox: [-5.83, 105.06, -8.91, 115.77],
|
|
proj4: '+proj=longlat +ellps=bessel +towgs84=-377,681,-50,0,0,0,0 +pm=jakarta +no_defs',
|
|
name: 'Batavia (Jakarta)',
|
|
};
|
|
|
|
proj4.defs(projSpec.code, projSpec.proj4);
|
|
register(proj4);
|
|
|
|
const proj = getProjection(projSpec.code);
|
|
const transform = getTransform('EPSG:4326', proj);
|
|
const extent = applyTransform([projSpec.bbox[1], projSpec.bbox[2], projSpec.bbox[3], projSpec.bbox[0]], transform);
|
|
proj.setExtent(extent);
|
|
const newView = new View({
|
|
projection: proj,
|
|
});
|
|
|
|
setTimeout(() => {
|
|
map.setView(newView);
|
|
newView.fit(extent);
|
|
}, 5000);
|
|
|
|
/**
|
|
* ==================================================
|
|
* # Custom Control
|
|
* ==================================================
|
|
*/
|
|
|
|
interface CustomControlOptions extends ControlOptions {
|
|
name?: string;
|
|
}
|
|
|
|
class CustomControl extends Control {
|
|
element: HTMLElement;
|
|
name: string;
|
|
mapViewport?: HTMLElement;
|
|
private readonly _boundListener: (e: Event) => void;
|
|
private readonly _eventKeys: EventsKey[];
|
|
|
|
constructor(options: CustomControlOptions = {}) {
|
|
options.element = document.createElement('div');
|
|
options.element.className = 'ol-custom-control ol-unselectable ol-control';
|
|
super(options);
|
|
this.name = options.name || this.constructor.name;
|
|
this._boundListener = this._listener.bind(this);
|
|
this._eventKeys = [];
|
|
}
|
|
|
|
// Override
|
|
setMap(map: PluggableMap) {
|
|
super.setMap(map);
|
|
unByKey(this._eventKeys);
|
|
this._eventKeys.splice(0);
|
|
|
|
if (this.mapViewport) this.mapViewport.removeEventListener('click', this._boundListener);
|
|
|
|
this.mapViewport = map ? map.getViewport() : undefined;
|
|
|
|
if (!this.mapViewport) return;
|
|
|
|
this.mapViewport.addEventListener('click', this._boundListener);
|
|
const view = map.getView();
|
|
this._eventKeys.push(
|
|
view.on('change:center', evt => {
|
|
console.log(evt.oldValue, view.getCenter());
|
|
}),
|
|
);
|
|
}
|
|
|
|
private _listener(evt: MouseEvent) {
|
|
const mapEvent = new MapBrowserEvent(evt.type, this.getMap(), evt);
|
|
console.log(mapEvent);
|
|
}
|
|
}
|
|
|
|
map.addControl(new CustomControl());
|
|
|
|
/**
|
|
* ==================================================
|
|
* # Overlay
|
|
* ==================================================
|
|
*/
|
|
|
|
const overlay = new Overlay({
|
|
position: fromLonLat([0, 0]),
|
|
element: document.createElement('div'),
|
|
});
|
|
|
|
map.addOverlay(overlay);
|
|
|
|
map.on('click', evt => {
|
|
if (overlay.getPosition() === undefined) overlay.setPosition(evt.coordinate);
|
|
else overlay.setPosition(undefined);
|
|
});
|
|
|
|
/**
|
|
* ==================================================
|
|
* # ol/array.stableSort
|
|
* ==================================================
|
|
*/
|
|
|
|
const arr = Array(10)
|
|
.fill(0)
|
|
.map((_, i) => i);
|
|
|
|
stableSort(arr, (a: number, b: number) => (a < b ? 1 : a > b ? -1 : 0));
|