1 //= require maplibre/map
2 //= require terra-draw/dist/terra-draw.umd
3 //= require terra-draw-maplibre-gl-adapter/dist/terra-draw-maplibre-gl-adapter.umd
5 /* globals terraDraw, terraDrawMaplibreGlAdapter */
8 const COORDINATES_FIELD_ID = "moderation_zone_zone";
9 const POSTGIS_LINE_POINTS_REGEXP = /[0-9-][ 0-9.,-]+/;
10 const SELECT_MODE_OPTIONS = {
16 midpoints: { draggable: true },
21 // Disallow resizing of the geometry from a given origin.
29 const baseMap = new OSM.MapLibre.SecondaryMap();
31 baseMap.once("style.load", () => {
33 const draw = createTerraDrawInstance(baseMap);
34 draw.on("finish", createTerraDrawFinishHandler(draw));
35 loadData(baseMap, draw);
37 // MapLibre is swallowing these exceptions silently, so I had
38 // to add this to know why my code was failing as I went.
39 console.error(e); // eslint-disable-line no-console
44 function createTerraDrawInstance(map) {
45 return new terraDraw.TerraDraw({
46 adapter: new terraDrawMaplibreGlAdapter.TerraDrawMapLibreGLAdapter({
51 new terraDraw.TerraDrawPolygonMode(),
52 new terraDraw.TerraDrawSelectMode(SELECT_MODE_OPTIONS)
57 function createTerraDrawFinishHandler(draw) {
58 return function (id, { mode, action }) {
59 if (mode === "polygon") {
60 draw.setMode("select");
61 } else if (mode === "select") {
64 throw new Error(`Unexpected mode "${mode}" (action: "${action}")`);
67 const feature = draw.getSnapshotFeature(id);
69 throw new Error(`Could not find feature with id ${id}`);
72 writeFormField(COORDINATES_FIELD_ID, feature);
76 function loadData(map, draw) {
77 const feature = readFormField(COORDINATES_FIELD_ID);
79 startTerraDrawForEdit(draw, feature);
80 map.fitBounds(featureToBox(feature), { radius: 100 });
82 startTerraDrawForNew(draw);
86 function readFormField(fieldId) {
87 const target = document.getElementById(fieldId);
89 throw new Error(`Could not find field #${fieldId}`);
92 const cleanValue = target.value.trim();
93 if (cleanValue === "") {
97 const match = POSTGIS_LINE_POINTS_REGEXP.exec(cleanValue);
99 throw new Error(`Unexpected value in field #${fieldId}. Expected a WKT geometry, but found: ${target.value}`);
102 const coordinatesString = match[0];
103 const pointStrings = coordinatesString.split(",").map(s => s.trim());
104 const points = pointStrings.map(s => s.split(" ")).map(pairs => pairs.map(parseFloat));
109 coordinates: [points]
117 function startTerraDrawForEdit(draw, feature) {
119 draw.setMode("polygon");
120 const results = draw.addFeatures([feature]);
121 const invalidFeatures = [];
122 results.forEach(r => {
124 invalidFeatures.push(r);
127 if (invalidFeatures.length > 0) {
128 const invalidFeaturesString = invalidFeatures.map(JSON.stringify).join("\n");
129 throw new Error(`Failed to load features into TerraDraw:\n${invalidFeaturesString}`);
131 draw.setMode("select");
134 function startTerraDrawForNew(draw) {
136 draw.setMode("polygon");
139 function writeFormField(fieldId, feature) {
140 const coordinatesString = feature.geometry.coordinates[0]
141 .map(([lon, lat]) => `${lon} ${lat}`)
143 const target = document.getElementById(fieldId);
144 target.value = `POLYGON((\n${coordinatesString}\n))`;
147 function featureToBox(feature) {
148 const points = feature.geometry.coordinates[0];
149 const seed = new maplibregl.LngLatBounds(points[0], points[0]);
150 return points.reduce((bounds, point) => bounds.extend(point), seed);