From 69429ada99e6c568906a0203f98032f89f6f96eb Mon Sep 17 00:00:00 2001 From: QuanGiap Date: Sat, 7 Oct 2023 14:33:59 -0700 Subject: [PATCH 1/6] feat: add Geometry file to determine point inside polygone --- package-lock.json | 15 ++- package.json | 1 + src/Alert.js | 10 +- src/Geometry.js | 225 ++++++++++++++++++++++++++++++++++ src/Map.js | 305 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 552 insertions(+), 4 deletions(-) create mode 100644 src/Geometry.js diff --git a/package-lock.json b/package-lock.json index 24bdddb..7c95d3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "treetracker-web-map-core", - "version": "2.6.0", + "version": "2.7.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "treetracker-web-map-core", - "version": "2.6.0", + "version": "2.7.2", "license": "ISC", "dependencies": { "axios": "^0.24.0", @@ -14,6 +14,7 @@ "events": "^3.3.0", "expect-runtime": "^0.10.1", "leaflet": "^1.7.1", + "leaflet-draw": "^1.0.4", "leaflet-utfgrid": "git+https://github.com/dadiorchen/Leaflet.UTFGrid.git", "leaflet.gridlayer.googlemutant": "^0.12.1", "lodash": "^4.17.21", @@ -9137,6 +9138,11 @@ "resolved": "https://registry.npm.taobao.org/leaflet/download/leaflet-1.7.1.tgz", "integrity": "sha1-ENaEkW7f4b9B1oijuXEnwDIqKhk=" }, + "node_modules/leaflet-draw": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/leaflet-draw/-/leaflet-draw-1.0.4.tgz", + "integrity": "sha512-rsQ6saQO5ST5Aj6XRFylr5zvarWgzWnrg46zQ1MEOEIHsppdC/8hnN8qMoFvACsPvTioAuysya/TVtog15tyAQ==" + }, "node_modules/leaflet-utfgrid": { "version": "0.3.0", "resolved": "git+ssh://git@github.com/dadiorchen/Leaflet.UTFGrid.git#2bdd74c2ca5298bcc820bc9e0deeb1ae69556526", @@ -20332,6 +20338,11 @@ "resolved": "https://registry.npm.taobao.org/leaflet/download/leaflet-1.7.1.tgz", "integrity": "sha1-ENaEkW7f4b9B1oijuXEnwDIqKhk=" }, + "leaflet-draw": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/leaflet-draw/-/leaflet-draw-1.0.4.tgz", + "integrity": "sha512-rsQ6saQO5ST5Aj6XRFylr5zvarWgzWnrg46zQ1MEOEIHsppdC/8hnN8qMoFvACsPvTioAuysya/TVtog15tyAQ==" + }, "leaflet-utfgrid": { "version": "git+ssh://git@github.com/dadiorchen/Leaflet.UTFGrid.git#2bdd74c2ca5298bcc820bc9e0deeb1ae69556526", "from": "leaflet-utfgrid@git+https://github.com/dadiorchen/Leaflet.UTFGrid.git", diff --git a/package.json b/package.json index f826e61..3540c2d 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "events": "^3.3.0", "expect-runtime": "^0.10.1", "leaflet": "^1.7.1", + "leaflet-draw": "^1.0.4", "leaflet-utfgrid": "git+https://github.com/dadiorchen/Leaflet.UTFGrid.git", "leaflet.gridlayer.googlemutant": "^0.12.1", "lodash": "^4.17.21", diff --git a/src/Alert.js b/src/Alert.js index c79cdb6..3221e15 100644 --- a/src/Alert.js +++ b/src/Alert.js @@ -2,7 +2,9 @@ import './style.css' export default class Alert { - constructor() {} + constructor() { + this.id = 0 + } mount(element) { // create a div and mount to the element @@ -26,11 +28,15 @@ export default class Alert { element.appendChild(this.alert) } - show(message) { + show(message, times) { + clearTimeout(this.id) document.getElementsByClassName( 'greenstand-alert-message-box', )[0].innerHTML = message this.alert.style.display = 'block' + if (times) { + this.id = setTimeout(() => this.hide(), times) + } } hide() { diff --git a/src/Geometry.js b/src/Geometry.js new file mode 100644 index 0000000..2aa69b3 --- /dev/null +++ b/src/Geometry.js @@ -0,0 +1,225 @@ +class Geometry { + constructor() {} + //check if point is in between 2 other points + #isInLine(line, point) { + return ( + point.lon <= Math.max(line.p1.lon, line.p2.lon) && + point.lon >= Math.min(line.p1.lon, line.p2.lon) && + point.lat <= Math.max(line.p1.lat, line.p2.lat) && + point.lat >= Math.min(line.p1.lat, line.p2.lat) + ) + } + #direction(p1, p2, p3) { + let val = + (p2.lat - p1.lat) * (p3.lon - p2.lon) - + (p2.lon - p1.lon) * (p3.lat - p2.lat) + if (val == 0) { + // Collinear + return 0 + } else if (val < 0) { + // Anti-clockwise direction + return 2 + } + // Clockwise direction + else return 1 + } + #getIntersectPoint(l1, l2) { + //make line equation y=mx+b + let m1 = (l1.p1.lat - l1.p2.lat) / (l1.p1.lon - l1.p2.lon) + let m2 = (l2.p1.lat - l2.p2.lat) / (l2.p1.lon - l2.p2.lon) + let b1 = l1.p1.lat - m1 * l1.p1.lon + let b2 = l2.p1.lat - m2 * l2.p1.lon + console.log(m1, m2, b1, b2) + let x = (b1 - b2) / (m2 - m1) + let y = m1 * x + b1 + return { + lat: y, + lon: x, + } + } + #isIntersect(l1, l2) { + let dir1 = this.#direction(l1.p1, l1.p2, l2.p1) + let dir2 = this.#direction(l1.p1, l1.p2, l2.p2) + let dir3 = this.#direction(l2.p1, l2.p2, l1.p1) + let dir4 = this.#direction(l2.p1, l2.p2, l1.p2) + //if interecting + if (dir1 !== dir2 && dir3 !== dir4) { + return true + } + // When p2 of line2 are on the line1 + if (dir1 == 0 && this.#isInLine(l1, l2.p1)) { + return true + } + // When p1 of line2 are on the line1 + if (dir2 == 0 && this.#isInLine(l1, l2.p2)) { + return true + } + // When p2 of line1 are on the line2 + if (dir3 == 0 && this.#isInLine(l2, l1.p1)) { + return true + } + // When p1 of line1 are on the line2 + if (dir4 == 0 && this.#isInLine(l2, l1.p2)) { + return true + } + return false + } + isValidPoly(poly) { + let n = poly.length + // When polygon has less than 3 edge, it is not polygon + if (n < 3) { + return false + } + const sides = [] + let i = 0 + do { + // Forming a line from two consecutive points of poly + let i2 = (i + 1) % n + let lat1 = poly[i].lat + let lng1 = poly[i].lng + let lat2 = poly[i2].lat + let lng2 = poly[i2].lng + let point1 = new Point(lng1, lat1) + let point2 = new Point(lng2, lat2) + let side = new Line(point1, point2) + console.log(`Create side with (${lng1},${lat1}) and (${lng2},${lat2})`) + sides.push(side) + i = i2 + } while (i != 0) + let m = sides.length + for (i = 0; i < m; i++) { + for (let j = 0; j < m; j++) { + //successive lines can have intersect point + if (i + 1 == j || i == j || i - 1 == j) { + continue + } + if (this.#isIntersect(sides[i], sides[j])) { + const intersectPoint = this.#getIntersectPoint(sides[i], sides[j]) + if (this.#isInLine(sides[i], intersectPoint)) { + return false + } + } + } + } + return true + } + /** + * return all indexes of points that is inside the polygone + * @returns indexes of points + */ + getPointsInsidePoly(poly, points = []) { + //check if polygone is valid + if (!this.isValidPoly(poly)) { + return [] + } + let result = [] + let n = poly.length + points.forEach((p, index) => { + let inLine = false + // Create a point at infinity, lat is same as point p + let tmp = new Point(p.lon, 9999) + let curP = new Point(p.lon, p.lat) + let exline = new Line(curP, tmp) + let count = 0 + let i = 0 + do { + // Forming a line from two consecutive points of poly + let i2 = (i + 1) % n + let lat1 = poly[i].lat + let lng1 = poly[i].lng + let lat2 = poly[i2].lat + let lng2 = poly[i2].lng + let point1 = new Point(lng1, lat1) + let point2 = new Point(lng2, lat2) + let side = new Line(point1, point2) + if (this.#isIntersect(side, exline)) { + // If side is intersects exline + if ( + this.#direction(side.p1, p, side.p2) == 0 && + this.#isInLine(side, p) + ) { + inLine = true + break + } + // if count is odd, point is inside the polygone + count++ + } + i = i2 + } while (i != 0) + if (count % 2 !== 0 || inLine) result.push(index) + }) + return result + } +} +class Point { + //int lon, lat; + constructor(lon, lat) { + this.lon = lon + this.lat = lat + } +} + +class Line { + //Point p1, p2; + constructor(p1, p2) { + this.p1 = p1 + this.p2 = p2 + } +} + +const poly = [ + { + lng: 1, + lat: 1, + }, + { + lng: 5, + lat: 7, + }, + { + lng: 2, + lat: 10, + }, + { + lng: 1, + lat: 7, + }, +] + +const points = [ + { + lon: 1.6, + lat: 2.14, + }, + { + lon: 4.94, + lat: 6.71, + }, + { + lon: 6, + lat: 9.5, + }, + { + lon: 0.35, + lat: 7.04, + }, + { + lon: 5, + lat: 1, + }, + { + lon: 2.5, + lat: -0.04, + }, +] + +const geo = new Geometry() +// const result = geo.getPointsInsidePoly(poly,points); +// result.forEach(val=>console.log(points[val])); +// let point1 = new Point(1,4); +// let point2 = new Point(8,9); +// let point3 = new Point(5,1); +// let point4 = new Point(1,9); +// let line1 = new Line(point1,point2); +// let line2 = new Line(point3,point4); +console.log('Polygone is valid: ' + geo.isValidPoly(poly)) diff --git a/src/Map.js b/src/Map.js index b600e5e..76e177d 100644 --- a/src/Map.js +++ b/src/Map.js @@ -7,7 +7,9 @@ import expect from 'expect-runtime' import log from 'loglevel' import _ from 'lodash' import 'leaflet' +import 'leaflet-draw' import 'leaflet/dist/leaflet.css' +import 'leaflet-draw/dist/leaflet.draw.css' import 'leaflet-utfgrid/L.UTFGrid' import 'leaflet.gridlayer.googlemutant' @@ -1136,6 +1138,8 @@ export default class Map { } return null }) + console.log('Item output:') + console.log(items) if (items.length === 0) { log.info('Can not find data by ', url) throw new MapError('Can not find any data') @@ -1349,9 +1353,310 @@ export default class Map { await this._unselectMarker() await this._unloadTileServer() await this._loadTileServer() + await this._loadEditor() } } + async _loadEditor() { + //var map = L.map('map', {drawControl: true}).setView([51.505, -0.09], 13); + // L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { + // attribution: '© OpenStreetMap contributors' + // }).addTo(this.map); + // FeatureGroup is to store editable layers + var drawnItems = new window.L.FeatureGroup() + this.map.addLayer(drawnItems) + var drawControl = new window.L.Control.Draw({ + draw: { + marker: false, + polyline: false, + circlemarker: false, + polygon: { + allowIntersection: false, + }, + }, + edit: { + featureGroup: drawnItems, + poly: { + allowIntersection: false, + }, + }, + }) + this.map.addControl(drawControl) + var panel = window.L.control({ position: 'topright' }) + panel.onAdd = function (map) { + var div = window.L.DomUtil.create('div', 'info') + div.innerHTML = ` +
+

Tree Count: 0

+
` + return div + } + panel.addTo(this.map) + //using leaflet to draw a polygon, when finished, the polygon will be added to the map + this.map.on('draw:created', (e) => { + var type = e.layerType, + layer = e.layer + console.warn('polygon created:', e) + drawnItems.addLayer(layer) + //request api for tree count + var total = 100 + document.getElementById('treeTotal').innerHTML = total + this.alert.show('New polygon created', 2000) + }) + this.map.on('draw:edited', (e) => { + try { + var type = e.layerType, + layer = e.layer + console.warn('polygon edited:', e) + // throw new Error('This is a test') + // drawnItems.addLayer(layer) + // editControl.revertLayers(); + } catch (err) { + console.log('Got an error') + } + }) + + //draw polygon with points + // var polygon = window.L.polygon([ + //[8.43209,-13.20411], + //[8.43590333333333,-13.22193], + //[8.43593166666667,-13.2219616666667], + //[8.436,-13.22201], + //[8.438915,-13.2224366666667], + //[8.43918666666667,-13.2223233333333], + //[8.43689833333333,-13.2015233333333], + //[8.43560333333333,-13.2011566666667], + //[8.43559,-13.201155], + //[8.43398,-13.2019516666667], + //[8.43209,-13.20411], + // ]).addTo(this.map); + + //draw array of points on the map + var points = [ + [8.436383333333334, -13.216488333333333], + [8.436333333333332, -13.216481666666668], + [8.43645, -13.216758333333333], + [8.436435, -13.216708333333335], + [8.436451666666667, -13.216705000000001], + [8.436481666666667, -13.216643333333332], + [8.436716666666666, -13.216738333333334], + [8.436791666666666, -13.21668], + [8.43685, -13.216809999999999], + [8.437986666666665, -13.217251666666668], + [8.438048333333334, -13.217098333333334], + [8.438053333333333, -13.217056666666668], + [8.43804, -13.217238333333334], + [8.436851666666666, -13.201561666666665], + [8.43686, -13.201521666666668], + [8.436898333333334, -13.201523333333334], + [8.436878333333334, -13.201771666666666], + [8.436863333333333, -13.201833333333331], + [8.436925, -13.201775000000001], + [8.43559, -13.201155000000002], + [8.435603333333335, -13.201156666666668], + [8.435601666666667, -13.201196666666666], + [8.435585, -13.201181666666665], + [8.435615, -13.201214999999998], + [8.435651666666667, -13.20124], + [8.43565, -13.201243333333332], + [8.435626666666668, -13.201246666666668], + [8.435658333333333, -13.201273333333331], + [8.435638333333333, -13.201276666666669], + [8.435658333333333, -13.201285], + [8.435626666666668, -13.201296666666668], + [8.435618333333334, -13.201196666666666], + [8.434026666666666, -13.202038333333332], + [8.43401, -13.202024999999999], + [8.434001666666667, -13.202020000000001], + [8.433986666666668, -13.202020000000001], + [8.433951666666667, -13.202028333333333], + [8.433976666666666, -13.201998333333332], + [8.433976666666666, -13.201991666666666], + [8.433941666666668, -13.202011666666666], + [8.433969999999999, -13.201966666666666], + [8.43398, -13.201951666666666], + [8.433978333333332, -13.201954999999998], + [8.434726666666668, -13.202633333333331], + [8.434838333333333, -13.202781666666665], + [8.43489, -13.202779999999999], + [8.432089999999999, -13.204109999999998], + [8.432163333333333, -13.204093333333333], + [8.4322, -13.204015], + [8.432188333333333, -13.204058333333334], + [8.432178333333333, -13.204103333333334], + [8.432203333333332, -13.204043333333335], + [8.432496666666667, -13.204094999999999], + [8.432440000000001, -13.20409], + [8.432491666666666, -13.20409833333333], + [8.432513333333333, -13.204141666666665], + [8.432756666666668, -13.20406], + [8.432781666666667, -13.204081666666665], + [8.432705, -13.204656666666665], + [8.432768333333334, -13.204666666666666], + [8.432736666666667, -13.204600000000001], + [8.432763333333332, -13.204621666666666], + [8.432748333333333, -13.20462], + [8.432756666666668, -13.204591666666666], + [8.432686666666665, -13.205588333333333], + [8.432773333333333, -13.205568333333334], + [8.432816666666668, -13.205503333333334], + [8.432775, -13.205406666666667], + [8.438561666666667, -13.22227], + [8.438585, -13.22231], + [8.438591666666667, -13.222306666666668], + [8.438615, -13.222336666666669], + [8.438596666666665, -13.222293333333335], + [8.438631666666668, -13.22233], + [8.438643333333333, -13.222355], + [8.438661666666667, -13.222308333333334], + [8.43868, -13.222364999999998], + [8.438675, -13.222331666666665], + [8.4387, -13.222323333333334], + [8.438736666666667, -13.22236], + [8.438783333333333, -13.222385000000001], + [8.438753333333333, -13.222376666666666], + [8.438821666666666, -13.222375], + [8.438831666666665, -13.222349999999999], + [8.438833333333333, -13.222364999999998], + [8.438868333333334, -13.222375], + [8.438898333333333, -13.222375], + [8.438903333333334, -13.222405], + [8.438915, -13.222436666666665], + [8.438934999999999, -13.222411666666668], + [8.439033333333333, -13.222368333333334], + [8.439028333333333, -13.22234], + [8.439065, -13.222308333333334], + [8.439073333333333, -13.222336666666669], + [8.439141666666666, -13.222341666666667], + [8.43911, -13.22233], + [8.439148333333332, -13.222295], + [8.439118333333333, -13.222316666666666], + [8.439186666666666, -13.222323333333334], + [8.438526666666666, -13.222223333333334], + [8.438563333333333, -13.222273333333332], + [8.438536666666666, -13.222281666666667], + [8.438493333333334, -13.222251666666667], + [8.43848, -13.22222], + [8.438448333333334, -13.222263333333334], + [8.43846, -13.222236666666667], + [8.438440000000002, -13.222241666666665], + [8.438425, -13.222223333333334], + [8.438421666666667, -13.222238333333333], + [8.438421666666667, -13.22222], + [8.438403333333333, -13.222190000000001], + [8.43839, -13.222198333333331], + [8.438378333333333, -13.222230000000001], + [8.438506666666665, -13.222235000000001], + [8.438531666666668, -13.222266666666666], + [8.43855, -13.222291666666669], + [8.43858, -13.222274999999998], + [8.438625, -13.222321666666668], + [8.438501666666667, -13.222188333333333], + [8.438375, -13.222221666666666], + [8.438328333333335, -13.22222], + [8.438326666666667, -13.222256666666665], + [8.438363333333333, -13.222228333333332], + [8.438313333333333, -13.222181666666666], + [8.438351666666668, -13.222190000000001], + [8.4383, -13.222191666666667], + [8.438311666666667, -13.222185000000001], + [8.438293333333332, -13.222098333333333], + [8.43827, -13.222125000000002], + [8.436233333333332, -13.222013333333333], + [8.436283333333334, -13.222029999999998], + [8.43623, -13.221984999999998], + [8.436243333333334, -13.221975000000002], + [8.436213333333335, -13.222023333333334], + [8.436208333333333, -13.222001666666666], + [8.436196666666666, -13.221958333333335], + [8.436163333333333, -13.221975000000002], + [8.436161666666667, -13.221936666666666], + [8.436133333333334, -13.221941666666664], + [8.43615, -13.221975000000002], + [8.436110000000001, -13.221943333333336], + [8.436101666666667, -13.22192], + [8.435965000000001, -13.221866666666665], + [8.436123333333335, -13.22178], + [8.435995, -13.221875], + [8.436018333333333, -13.221865], + [8.435931666666667, -13.221961666666667], + [8.435923333333333, -13.221926666666665], + [8.43599, -13.221960000000001], + [8.436, -13.222010000000001], + [8.435953333333334, -13.221943333333336], + [8.436005, -13.221971666666665], + [8.436045, -13.22198], + [8.436005, -13.221984999999998], + [8.436108333333333, -13.221926666666665], + [8.435953333333334, -13.221955], + [8.436020000000001, -13.221941666666664], + [8.435903333333332, -13.221930000000002], + [8.435941666666668, -13.221948333333334], + [8.43589, -13.221826666666667], + [8.435955, -13.221251666666667], + [8.435966666666667, -13.221255000000001], + [8.435935, -13.221236666666668], + [8.436728333333333, -13.221738333333333], + [8.436766666666667, -13.221691666666667], + [8.436751666666668, -13.221713333333332], + [8.436803333333334, -13.221711666666666], + [8.436778333333333, -13.221748333333334], + [8.436733333333333, -13.22174], + [8.436855000000001, -13.221748333333334], + [8.436831666666667, -13.221793333333334], + [8.436851666666666, -13.221803333333332], + [8.436806666666666, -13.221761666666664], + [8.436851666666666, -13.221818333333333], + [8.436874999999999, -13.221763333333335], + [8.436810000000001, -13.221776666666665], + [8.43678, -13.221813333333333], + [8.436918333333333, -13.221908333333333], + [8.436743333333334, -13.221699999999998], + [8.436761666666666, -13.221705000000002], + [8.436778333333333, -13.221708333333334], + [8.436758333333334, -13.221728333333333], + [8.436795, -13.221713333333332], + [8.436835, -13.221741666666667], + [8.436798333333334, -13.221714999999998], + [8.43684, -13.221756666666666], + [8.436825, -13.221751666666668], + [8.436836666666666, -13.221849999999998], + [8.436923333333334, -13.221843333333334], + [8.436906666666665, -13.221826666666667], + ] + // draw points markers + // for (let i = 0; i < points.length; i++) { + // const point = points[i] + // const marker = window.L.marker(point, { + // icon: window.L.divIcon({ + // className: 'marker', + // html: `
`, + // iconSize: [20, 20], + // iconAnchor: [10, 10], + // }), + // }) + // marker.addTo(this.map) + // } + + //draw a path with points with width 5 + // const polyline = window.L.polyline(points, { + // color: 'yellow', + // weight: 8, + // }).addTo(this.map) + + //draw polygon with plogon() + + //focus on the polygon + //this.map.fitBounds(polygon.getBounds()); + + //focus on the points + // this.map.fitBounds(polyline.getBounds()) + } + clearSelection() { this._unselectMarker() } From 3b80e726e2cc6ca1cfc413d27dcc7eab1141699c Mon Sep 17 00:00:00 2001 From: QuanGiap Date: Sun, 17 Dec 2023 15:19:20 -0800 Subject: [PATCH 2/6] fix: clean up code --- src/Alert.js | 6 +- src/Geometry.js | 225 ---------------------------------- src/Map.js | 318 +++++++++--------------------------------------- 3 files changed, 63 insertions(+), 486 deletions(-) delete mode 100644 src/Geometry.js diff --git a/src/Alert.js b/src/Alert.js index 3221e15..d5f1e0f 100644 --- a/src/Alert.js +++ b/src/Alert.js @@ -28,14 +28,14 @@ export default class Alert { element.appendChild(this.alert) } - show(message, times) { + show(message, time) { clearTimeout(this.id) document.getElementsByClassName( 'greenstand-alert-message-box', )[0].innerHTML = message this.alert.style.display = 'block' - if (times) { - this.id = setTimeout(() => this.hide(), times) + if (time) { + this.id = setTimeout(() => this.hide(), time) } } diff --git a/src/Geometry.js b/src/Geometry.js deleted file mode 100644 index 2aa69b3..0000000 --- a/src/Geometry.js +++ /dev/null @@ -1,225 +0,0 @@ -class Geometry { - constructor() {} - //check if point is in between 2 other points - #isInLine(line, point) { - return ( - point.lon <= Math.max(line.p1.lon, line.p2.lon) && - point.lon >= Math.min(line.p1.lon, line.p2.lon) && - point.lat <= Math.max(line.p1.lat, line.p2.lat) && - point.lat >= Math.min(line.p1.lat, line.p2.lat) - ) - } - #direction(p1, p2, p3) { - let val = - (p2.lat - p1.lat) * (p3.lon - p2.lon) - - (p2.lon - p1.lon) * (p3.lat - p2.lat) - if (val == 0) { - // Collinear - return 0 - } else if (val < 0) { - // Anti-clockwise direction - return 2 - } - // Clockwise direction - else return 1 - } - #getIntersectPoint(l1, l2) { - //make line equation y=mx+b - let m1 = (l1.p1.lat - l1.p2.lat) / (l1.p1.lon - l1.p2.lon) - let m2 = (l2.p1.lat - l2.p2.lat) / (l2.p1.lon - l2.p2.lon) - let b1 = l1.p1.lat - m1 * l1.p1.lon - let b2 = l2.p1.lat - m2 * l2.p1.lon - console.log(m1, m2, b1, b2) - let x = (b1 - b2) / (m2 - m1) - let y = m1 * x + b1 - return { - lat: y, - lon: x, - } - } - #isIntersect(l1, l2) { - let dir1 = this.#direction(l1.p1, l1.p2, l2.p1) - let dir2 = this.#direction(l1.p1, l1.p2, l2.p2) - let dir3 = this.#direction(l2.p1, l2.p2, l1.p1) - let dir4 = this.#direction(l2.p1, l2.p2, l1.p2) - //if interecting - if (dir1 !== dir2 && dir3 !== dir4) { - return true - } - // When p2 of line2 are on the line1 - if (dir1 == 0 && this.#isInLine(l1, l2.p1)) { - return true - } - // When p1 of line2 are on the line1 - if (dir2 == 0 && this.#isInLine(l1, l2.p2)) { - return true - } - // When p2 of line1 are on the line2 - if (dir3 == 0 && this.#isInLine(l2, l1.p1)) { - return true - } - // When p1 of line1 are on the line2 - if (dir4 == 0 && this.#isInLine(l2, l1.p2)) { - return true - } - return false - } - isValidPoly(poly) { - let n = poly.length - // When polygon has less than 3 edge, it is not polygon - if (n < 3) { - return false - } - const sides = [] - let i = 0 - do { - // Forming a line from two consecutive points of poly - let i2 = (i + 1) % n - let lat1 = poly[i].lat - let lng1 = poly[i].lng - let lat2 = poly[i2].lat - let lng2 = poly[i2].lng - let point1 = new Point(lng1, lat1) - let point2 = new Point(lng2, lat2) - let side = new Line(point1, point2) - console.log(`Create side with (${lng1},${lat1}) and (${lng2},${lat2})`) - sides.push(side) - i = i2 - } while (i != 0) - let m = sides.length - for (i = 0; i < m; i++) { - for (let j = 0; j < m; j++) { - //successive lines can have intersect point - if (i + 1 == j || i == j || i - 1 == j) { - continue - } - if (this.#isIntersect(sides[i], sides[j])) { - const intersectPoint = this.#getIntersectPoint(sides[i], sides[j]) - if (this.#isInLine(sides[i], intersectPoint)) { - return false - } - } - } - } - return true - } - /** - * return all indexes of points that is inside the polygone - * @returns indexes of points - */ - getPointsInsidePoly(poly, points = []) { - //check if polygone is valid - if (!this.isValidPoly(poly)) { - return [] - } - let result = [] - let n = poly.length - points.forEach((p, index) => { - let inLine = false - // Create a point at infinity, lat is same as point p - let tmp = new Point(p.lon, 9999) - let curP = new Point(p.lon, p.lat) - let exline = new Line(curP, tmp) - let count = 0 - let i = 0 - do { - // Forming a line from two consecutive points of poly - let i2 = (i + 1) % n - let lat1 = poly[i].lat - let lng1 = poly[i].lng - let lat2 = poly[i2].lat - let lng2 = poly[i2].lng - let point1 = new Point(lng1, lat1) - let point2 = new Point(lng2, lat2) - let side = new Line(point1, point2) - if (this.#isIntersect(side, exline)) { - // If side is intersects exline - if ( - this.#direction(side.p1, p, side.p2) == 0 && - this.#isInLine(side, p) - ) { - inLine = true - break - } - // if count is odd, point is inside the polygone - count++ - } - i = i2 - } while (i != 0) - if (count % 2 !== 0 || inLine) result.push(index) - }) - return result - } -} -class Point { - //int lon, lat; - constructor(lon, lat) { - this.lon = lon - this.lat = lat - } -} - -class Line { - //Point p1, p2; - constructor(p1, p2) { - this.p1 = p1 - this.p2 = p2 - } -} - -const poly = [ - { - lng: 1, - lat: 1, - }, - { - lng: 5, - lat: 7, - }, - { - lng: 2, - lat: 10, - }, - { - lng: 1, - lat: 7, - }, -] - -const points = [ - { - lon: 1.6, - lat: 2.14, - }, - { - lon: 4.94, - lat: 6.71, - }, - { - lon: 6, - lat: 9.5, - }, - { - lon: 0.35, - lat: 7.04, - }, - { - lon: 5, - lat: 1, - }, - { - lon: 2.5, - lat: -0.04, - }, -] - -const geo = new Geometry() -// const result = geo.getPointsInsidePoly(poly,points); -// result.forEach(val=>console.log(points[val])); -// let point1 = new Point(1,4); -// let point2 = new Point(8,9); -// let point3 = new Point(5,1); -// let point4 = new Point(1,9); -// let line1 = new Line(point1,point2); -// let line2 = new Line(point3,point4); -console.log('Polygone is valid: ' + geo.isValidPoly(poly)) diff --git a/src/Map.js b/src/Map.js index 76e177d..4dc0c21 100644 --- a/src/Map.js +++ b/src/Map.js @@ -71,6 +71,8 @@ export default class Map { // mount element this._mountDomElement = null + //check if in drawing mode + this.isDrawingMode = false log.warn('map core version:', require('../package.json').version) } @@ -308,7 +310,7 @@ export default class Map { ) this.layerUtfGrid.on('click', (e) => { log.warn('click:', e) - if (e.data) { + if (e.data && !this.isDrawingMode) { this._clickMarker(Map._parseUtfData(e.data)) } }) @@ -972,6 +974,37 @@ export default class Map { : this.nearestTreeArrow.showArrow(placement) } + async _getTreesFromPoly(poly) { + try { + let polypoints = poly.map(({ lat, lng }) => { + return { + lat, + lon: lng, + } + }) + //add another first point to make polygon enclosed + polypoints.push({ lat: poly[0].lat, lon: poly[0].lng }) + this.alert.show('Collecting trees data') + const result = await this.requester.request({ + url: `${this.queryApiServerUrl}/gis`, + data: { + polygon: polypoints, + }, + headers: { 'Content-Type': 'application/json' }, + method: 'post', + }) + this.alert.hide() + return result + } catch (err) { + this.alert.show( + 'Can not collecting tree data, please try again later', + 5000, + ) + console.info(err.message || 'Unknown') + return null + } + } + async _moveToNearestTree() { const nearest = await this._getNearest() if (nearest) { @@ -1138,8 +1171,6 @@ export default class Map { } return null }) - console.log('Item output:') - console.log(items) if (items.length === 0) { log.info('Can not find data by ', url) throw new MapError('Can not find any data') @@ -1370,6 +1401,7 @@ export default class Map { marker: false, polyline: false, circlemarker: false, + circle: false, polygon: { allowIntersection: false, }, @@ -1395,266 +1427,36 @@ export default class Map { } panel.addTo(this.map) //using leaflet to draw a polygon, when finished, the polygon will be added to the map - this.map.on('draw:created', (e) => { - var type = e.layerType, + this.map.on('draw:created', async (e) => { + let type = e.layerType, layer = e.layer - console.warn('polygon created:', e) + let points = layer._latlngs[0] + //if polygone is valid, insert polygon to the map drawnItems.addLayer(layer) - //request api for tree count - var total = 100 + const result = await this._getTreesFromPoly(points) + var total = result?.trees?.length || 0 document.getElementById('treeTotal').innerHTML = total - this.alert.show('New polygon created', 2000) }) - this.map.on('draw:edited', (e) => { - try { - var type = e.layerType, - layer = e.layer - console.warn('polygon edited:', e) - // throw new Error('This is a test') - // drawnItems.addLayer(layer) - // editControl.revertLayers(); - } catch (err) { - console.log('Got an error') - } + this.map.on('draw:edited', async (e) => { + let layers = e.layers._layers + let polygon = Object.values(layers)[0] + const result = await this._getTreesFromPoly(polygon._latlngs[0]) + var total = result?.trees?.length || 0 + document.getElementById('treeTotal').innerHTML = total + }) + //enable drawing mode which prevent user move when clicking on icon tree or group + this.map.on('draw:drawstart ', (e) => { + this.isDrawingMode = true + }) + this.map.on('draw:drawstop ', (e) => { + this.isDrawingMode = false + }) + this.map.on('draw:editstart ', (e) => { + this.isDrawingMode = true + }) + this.map.on('draw:editstop ', (e) => { + this.isDrawingMode = false }) - - //draw polygon with points - // var polygon = window.L.polygon([ - //[8.43209,-13.20411], - //[8.43590333333333,-13.22193], - //[8.43593166666667,-13.2219616666667], - //[8.436,-13.22201], - //[8.438915,-13.2224366666667], - //[8.43918666666667,-13.2223233333333], - //[8.43689833333333,-13.2015233333333], - //[8.43560333333333,-13.2011566666667], - //[8.43559,-13.201155], - //[8.43398,-13.2019516666667], - //[8.43209,-13.20411], - // ]).addTo(this.map); - - //draw array of points on the map - var points = [ - [8.436383333333334, -13.216488333333333], - [8.436333333333332, -13.216481666666668], - [8.43645, -13.216758333333333], - [8.436435, -13.216708333333335], - [8.436451666666667, -13.216705000000001], - [8.436481666666667, -13.216643333333332], - [8.436716666666666, -13.216738333333334], - [8.436791666666666, -13.21668], - [8.43685, -13.216809999999999], - [8.437986666666665, -13.217251666666668], - [8.438048333333334, -13.217098333333334], - [8.438053333333333, -13.217056666666668], - [8.43804, -13.217238333333334], - [8.436851666666666, -13.201561666666665], - [8.43686, -13.201521666666668], - [8.436898333333334, -13.201523333333334], - [8.436878333333334, -13.201771666666666], - [8.436863333333333, -13.201833333333331], - [8.436925, -13.201775000000001], - [8.43559, -13.201155000000002], - [8.435603333333335, -13.201156666666668], - [8.435601666666667, -13.201196666666666], - [8.435585, -13.201181666666665], - [8.435615, -13.201214999999998], - [8.435651666666667, -13.20124], - [8.43565, -13.201243333333332], - [8.435626666666668, -13.201246666666668], - [8.435658333333333, -13.201273333333331], - [8.435638333333333, -13.201276666666669], - [8.435658333333333, -13.201285], - [8.435626666666668, -13.201296666666668], - [8.435618333333334, -13.201196666666666], - [8.434026666666666, -13.202038333333332], - [8.43401, -13.202024999999999], - [8.434001666666667, -13.202020000000001], - [8.433986666666668, -13.202020000000001], - [8.433951666666667, -13.202028333333333], - [8.433976666666666, -13.201998333333332], - [8.433976666666666, -13.201991666666666], - [8.433941666666668, -13.202011666666666], - [8.433969999999999, -13.201966666666666], - [8.43398, -13.201951666666666], - [8.433978333333332, -13.201954999999998], - [8.434726666666668, -13.202633333333331], - [8.434838333333333, -13.202781666666665], - [8.43489, -13.202779999999999], - [8.432089999999999, -13.204109999999998], - [8.432163333333333, -13.204093333333333], - [8.4322, -13.204015], - [8.432188333333333, -13.204058333333334], - [8.432178333333333, -13.204103333333334], - [8.432203333333332, -13.204043333333335], - [8.432496666666667, -13.204094999999999], - [8.432440000000001, -13.20409], - [8.432491666666666, -13.20409833333333], - [8.432513333333333, -13.204141666666665], - [8.432756666666668, -13.20406], - [8.432781666666667, -13.204081666666665], - [8.432705, -13.204656666666665], - [8.432768333333334, -13.204666666666666], - [8.432736666666667, -13.204600000000001], - [8.432763333333332, -13.204621666666666], - [8.432748333333333, -13.20462], - [8.432756666666668, -13.204591666666666], - [8.432686666666665, -13.205588333333333], - [8.432773333333333, -13.205568333333334], - [8.432816666666668, -13.205503333333334], - [8.432775, -13.205406666666667], - [8.438561666666667, -13.22227], - [8.438585, -13.22231], - [8.438591666666667, -13.222306666666668], - [8.438615, -13.222336666666669], - [8.438596666666665, -13.222293333333335], - [8.438631666666668, -13.22233], - [8.438643333333333, -13.222355], - [8.438661666666667, -13.222308333333334], - [8.43868, -13.222364999999998], - [8.438675, -13.222331666666665], - [8.4387, -13.222323333333334], - [8.438736666666667, -13.22236], - [8.438783333333333, -13.222385000000001], - [8.438753333333333, -13.222376666666666], - [8.438821666666666, -13.222375], - [8.438831666666665, -13.222349999999999], - [8.438833333333333, -13.222364999999998], - [8.438868333333334, -13.222375], - [8.438898333333333, -13.222375], - [8.438903333333334, -13.222405], - [8.438915, -13.222436666666665], - [8.438934999999999, -13.222411666666668], - [8.439033333333333, -13.222368333333334], - [8.439028333333333, -13.22234], - [8.439065, -13.222308333333334], - [8.439073333333333, -13.222336666666669], - [8.439141666666666, -13.222341666666667], - [8.43911, -13.22233], - [8.439148333333332, -13.222295], - [8.439118333333333, -13.222316666666666], - [8.439186666666666, -13.222323333333334], - [8.438526666666666, -13.222223333333334], - [8.438563333333333, -13.222273333333332], - [8.438536666666666, -13.222281666666667], - [8.438493333333334, -13.222251666666667], - [8.43848, -13.22222], - [8.438448333333334, -13.222263333333334], - [8.43846, -13.222236666666667], - [8.438440000000002, -13.222241666666665], - [8.438425, -13.222223333333334], - [8.438421666666667, -13.222238333333333], - [8.438421666666667, -13.22222], - [8.438403333333333, -13.222190000000001], - [8.43839, -13.222198333333331], - [8.438378333333333, -13.222230000000001], - [8.438506666666665, -13.222235000000001], - [8.438531666666668, -13.222266666666666], - [8.43855, -13.222291666666669], - [8.43858, -13.222274999999998], - [8.438625, -13.222321666666668], - [8.438501666666667, -13.222188333333333], - [8.438375, -13.222221666666666], - [8.438328333333335, -13.22222], - [8.438326666666667, -13.222256666666665], - [8.438363333333333, -13.222228333333332], - [8.438313333333333, -13.222181666666666], - [8.438351666666668, -13.222190000000001], - [8.4383, -13.222191666666667], - [8.438311666666667, -13.222185000000001], - [8.438293333333332, -13.222098333333333], - [8.43827, -13.222125000000002], - [8.436233333333332, -13.222013333333333], - [8.436283333333334, -13.222029999999998], - [8.43623, -13.221984999999998], - [8.436243333333334, -13.221975000000002], - [8.436213333333335, -13.222023333333334], - [8.436208333333333, -13.222001666666666], - [8.436196666666666, -13.221958333333335], - [8.436163333333333, -13.221975000000002], - [8.436161666666667, -13.221936666666666], - [8.436133333333334, -13.221941666666664], - [8.43615, -13.221975000000002], - [8.436110000000001, -13.221943333333336], - [8.436101666666667, -13.22192], - [8.435965000000001, -13.221866666666665], - [8.436123333333335, -13.22178], - [8.435995, -13.221875], - [8.436018333333333, -13.221865], - [8.435931666666667, -13.221961666666667], - [8.435923333333333, -13.221926666666665], - [8.43599, -13.221960000000001], - [8.436, -13.222010000000001], - [8.435953333333334, -13.221943333333336], - [8.436005, -13.221971666666665], - [8.436045, -13.22198], - [8.436005, -13.221984999999998], - [8.436108333333333, -13.221926666666665], - [8.435953333333334, -13.221955], - [8.436020000000001, -13.221941666666664], - [8.435903333333332, -13.221930000000002], - [8.435941666666668, -13.221948333333334], - [8.43589, -13.221826666666667], - [8.435955, -13.221251666666667], - [8.435966666666667, -13.221255000000001], - [8.435935, -13.221236666666668], - [8.436728333333333, -13.221738333333333], - [8.436766666666667, -13.221691666666667], - [8.436751666666668, -13.221713333333332], - [8.436803333333334, -13.221711666666666], - [8.436778333333333, -13.221748333333334], - [8.436733333333333, -13.22174], - [8.436855000000001, -13.221748333333334], - [8.436831666666667, -13.221793333333334], - [8.436851666666666, -13.221803333333332], - [8.436806666666666, -13.221761666666664], - [8.436851666666666, -13.221818333333333], - [8.436874999999999, -13.221763333333335], - [8.436810000000001, -13.221776666666665], - [8.43678, -13.221813333333333], - [8.436918333333333, -13.221908333333333], - [8.436743333333334, -13.221699999999998], - [8.436761666666666, -13.221705000000002], - [8.436778333333333, -13.221708333333334], - [8.436758333333334, -13.221728333333333], - [8.436795, -13.221713333333332], - [8.436835, -13.221741666666667], - [8.436798333333334, -13.221714999999998], - [8.43684, -13.221756666666666], - [8.436825, -13.221751666666668], - [8.436836666666666, -13.221849999999998], - [8.436923333333334, -13.221843333333334], - [8.436906666666665, -13.221826666666667], - ] - // draw points markers - // for (let i = 0; i < points.length; i++) { - // const point = points[i] - // const marker = window.L.marker(point, { - // icon: window.L.divIcon({ - // className: 'marker', - // html: `
`, - // iconSize: [20, 20], - // iconAnchor: [10, 10], - // }), - // }) - // marker.addTo(this.map) - // } - - //draw a path with points with width 5 - // const polyline = window.L.polyline(points, { - // color: 'yellow', - // weight: 8, - // }).addTo(this.map) - - //draw polygon with plogon() - - //focus on the polygon - //this.map.fitBounds(polygon.getBounds()); - - //focus on the points - // this.map.fitBounds(polyline.getBounds()) } clearSelection() { From 67cd17a1fd8beb8fee69aa49211427b8a5199399 Mon Sep 17 00:00:00 2001 From: QuanGiap Date: Mon, 25 Dec 2023 22:49:31 -0800 Subject: [PATCH 3/6] feat: add new event MULTIPLE_TREES_SELECTED --- dist/index.html | 3 +- src/Map.js | 126 ++++++++++++++++++++++++++++++++++++++++++++--- src/Map.test.mjs | 24 +++++++++ 3 files changed, 146 insertions(+), 7 deletions(-) diff --git a/dist/index.html b/dist/index.html index 8690013..455e7b6 100644 --- a/dist/index.html +++ b/dist/index.html @@ -201,11 +201,12 @@
Select/highlight tree
const parameters = getParameters(); map = new greenstand.Map({ onLoad: () => console.log("onload"), - onClickTree: () => console.log("onClickTree"), onFindNearestAt: () => console.log("onFindNearstAt"), onError: () => console.log("onError"), }); map.on(greenstand.Map.REGISTERED_EVENTS.MOVE_END, handleMoveEnd); + map.on(greenstand.Map.REGISTERED_EVENTS.TREE_SELECTED, (data) => console.log(data)); + map.on(greenstand.Map.REGISTERED_EVENTS.MULTIPLE_TREES_SELECTED, (data) => console.log(data)); map.mount(document.getElementById("map")); map.setFilters(parameters); }; diff --git a/src/Map.js b/src/Map.js index 4dc0c21..f48fbf7 100644 --- a/src/Map.js +++ b/src/Map.js @@ -33,8 +33,14 @@ export default class Map { // events static REGISTERED_EVENTS = { TREE_SELECTED: 'tree-selected', + MULTIPLE_TREES_SELECTED: 'multiple-trees-selected', TREE_UNSELECTED: 'tree-unselected', MOVE_END: 'move-end', + LOAD: 'load', + TREE_CLICKED: 'tree-clicked', + //not implemented this event yet + // FIND_NEAREST: 'find-nearest', + ERROR: 'error', } constructor(options) { @@ -48,7 +54,8 @@ export default class Map { tileServerUrl: 'https://{s}.treetracker.org/tiles/', tileServerSubdomains: ['prod-k8s'], apiServerUrl: 'https://prod-k8s.treetracker.org/webmap/', - queryApiServerUrl: 'https://prod-k8s.treetracker.org/query', + // queryApiServerUrl: 'https://prod-k8s.treetracker.org/query', + queryApiServerUrl: 'http://localhost:3006', debug: false, moreEffect: true, filters: null, @@ -73,7 +80,21 @@ export default class Map { //check if in drawing mode this.isDrawingMode = false + log.warn('map core version:', require('../package.json').version) + + // Deprecation warnings + let deprecatedMethods = [ + 'onLoad', + 'onClickTree', + 'onFindNearestAt', + 'onError', + ] + deprecatedMethods.forEach((method) => { + if (this[method]) { + log.warn(`${method} is deprecated. Use map.on() instead.`) + } + }) } /** *************************** static *************************** */ @@ -522,6 +543,9 @@ export default class Map { if (this.onClickTree) { this.onClickTree(data) } + if (this.events.listenerCount(Map.REGISTERED_EVENTS.TREE_CLICKED) > 0) { + this.events.emit(Map.REGISTERED_EVENTS.TREE_CLICKED, data) + } } else if (data.type === 'cluster') { if (data.zoom_to) { log.info('found zoom to:', data.zoom_to) @@ -1342,7 +1366,9 @@ export default class Map { if (this.onLoad) { this.onLoad() } - + if (this.events.listenerCount(Map.REGISTERED_EVENTS.LOAD) > 0) { + this.events.emit(Map.REGISTERED_EVENTS.LOAD) + } if (this.debug) { await this._loadDebugLayer() } @@ -1353,15 +1379,61 @@ export default class Map { if (this.onError) { this.onError(e) } + if (this.events.listenerCount(Map.REGISTERED_EVENTS.ERROR) > 0) { + this.events.emit(Map.REGISTERED_EVENTS.ERROR, e) + } } } } on(eventName, handler) { + const isValidEvent = Object.values(Map.REGISTERED_EVENTS).includes( + eventName, + ) + if (!isValidEvent) { + log.error('Invalid event name:', eventName) + return + } //TODO check event name enum if (handler) { log.info('register event:', eventName) this.events.on(eventName, handler) + } else { + log.error('No handler provided for event:', eventName) + } + } + + off(eventName, handler) { + const isValidEvent = Object.values(Map.REGISTERED_EVENTS).includes( + eventName, + ) + if (!isValidEvent) { + log.error('Invalid event name:', eventName) + return + } + + if (handler) { + log.info('remove event:', eventName) + this.events.off(eventName, handler) + } else { + log.error('No handler provided for event removal:', eventName) + } + } + + once(eventName, handler) { + const isValidEvent = Object.values(Map.REGISTERED_EVENTS).includes( + eventName, + ) + if (!isValidEvent) { + log.error('Invalid event name:', eventName) + return + } + + if (handler) { + log.info('register one-time event:', eventName) + this.events.once(eventName, handler) + } else { + log.error('No handler provided for this one-time event:', eventName) } } @@ -1413,6 +1485,15 @@ export default class Map { }, }, }) + var editOnlyControl = new window.L.Control.Draw({ + draw: false, + edit: { + featureGroup: drawnItems, + poly: { + allowIntersection: false, + }, + }, + }) this.map.addControl(drawControl) var panel = window.L.control({ position: 'topright' }) panel.onAdd = function (map) { @@ -1431,18 +1512,51 @@ export default class Map { let type = e.layerType, layer = e.layer let points = layer._latlngs[0] - //if polygone is valid, insert polygon to the map drawnItems.addLayer(layer) + //disable draw tool + this.map.removeControl(drawControl) + this.map.addControl(editOnlyControl) const result = await this._getTreesFromPoly(points) var total = result?.trees?.length || 0 document.getElementById('treeTotal').innerHTML = total + if ( + this.events.listenerCount( + Map.REGISTERED_EVENTS.MULTIPLE_TREES_SELECTED, + ) > 0 + ) { + this.events.emit( + Map.REGISTERED_EVENTS.MULTIPLE_TREES_SELECTED, + result?.trees || [], + ) + } }) this.map.on('draw:edited', async (e) => { let layers = e.layers._layers let polygon = Object.values(layers)[0] - const result = await this._getTreesFromPoly(polygon._latlngs[0]) - var total = result?.trees?.length || 0 - document.getElementById('treeTotal').innerHTML = total + //if no polygon edited + if (polygon) { + const result = await this._getTreesFromPoly(polygon._latlngs[0]) + var total = result?.trees?.length || 0 + document.getElementById('treeTotal').innerHTML = total + if ( + this.events.listenerCount( + Map.REGISTERED_EVENTS.MULTIPLE_TREES_SELECTED, + ) > 0 + ) { + this.events.emit( + Map.REGISTERED_EVENTS.MULTIPLE_TREES_SELECTED, + result?.trees || [], + ) + } + } + }) + this.map.on('draw:deleted', async (e) => { + //enable draw tool if all polygons deleted + if (drawnItems.getLayers().length == 0) { + this.map.removeControl(editOnlyControl) + this.map.addControl(drawControl) + document.getElementById('treeTotal').innerHTML = 0 + } }) //enable drawing mode which prevent user move when clicking on icon tree or group this.map.on('draw:drawstart ', (e) => { diff --git a/src/Map.test.mjs b/src/Map.test.mjs index 532cc5e..bfc9791 100644 --- a/src/Map.test.mjs +++ b/src/Map.test.mjs @@ -45,4 +45,28 @@ describe('Map', () => { zoomLevel: 3, }) }) + + // it("Test trigger events",async()=>{ + // const request = jest.fn(() => response) + // Requester.mockImplementation(() => ({ + // request, + // })) + // const event_check = { + // tree_selected:0, + // } + // const map = new Map({ + // userid: '1', + // width: 1440, + // height: 510, + // moreEffect: false, + // filters: { + // wallet: 'mayeda', + // }, + // //function to test error event + // _mountComponents: ()=>{ + // throw new Error("Error event"); + // } + // }) + // map.on(map.REGISTERED_EVENTS.TREE_SELECTED) + // }) }) From f478ad1cd234da9baea1aa93589e7a01959dc415 Mon Sep 17 00:00:00 2001 From: QuanGiap Date: Sat, 30 Dec 2023 15:48:31 -0800 Subject: [PATCH 4/6] fix: change to prod-query --- src/Map.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Map.js b/src/Map.js index f48fbf7..95d1667 100644 --- a/src/Map.js +++ b/src/Map.js @@ -54,8 +54,7 @@ export default class Map { tileServerUrl: 'https://{s}.treetracker.org/tiles/', tileServerSubdomains: ['prod-k8s'], apiServerUrl: 'https://prod-k8s.treetracker.org/webmap/', - // queryApiServerUrl: 'https://prod-k8s.treetracker.org/query', - queryApiServerUrl: 'http://localhost:3006', + queryApiServerUrl: 'https://prod-k8s.treetracker.org/query', debug: false, moreEffect: true, filters: null, From eb27174190b0f2c1c70fc98e363ecffd3468ecbb Mon Sep 17 00:00:00 2001 From: QuanGiap Date: Sat, 23 Mar 2024 14:51:06 -0700 Subject: [PATCH 5/6] fix: seperate drawing tool into different file --- src/DrawTool.js | 88 ++++++++++++++++++++++++++++++++++++++++++++ src/Map.js | 98 ++++++------------------------------------------- 2 files changed, 100 insertions(+), 86 deletions(-) create mode 100644 src/DrawTool.js diff --git a/src/DrawTool.js b/src/DrawTool.js new file mode 100644 index 0000000..14ec08d --- /dev/null +++ b/src/DrawTool.js @@ -0,0 +1,88 @@ +import 'leaflet-draw' +import 'leaflet-draw/dist/leaflet.draw.css' + +class DrawTool { + constructor(map) { + this.map = map + this.isDrawingMode = false + this._loadEditor() + this.onSelecetMultTree = null + } + onSelecetMultiplePoints(funct) { + this.onSelecetMultPoints = funct + } + async _loadEditor() { + // FeatureGroup is to store editable layers + var drawnItems = new window.L.FeatureGroup() + this.map.addLayer(drawnItems) + var drawControl = new window.L.Control.Draw({ + draw: { + marker: false, + polyline: false, + circlemarker: false, + circle: false, + polygon: { + allowIntersection: false, + }, + }, + edit: { + featureGroup: drawnItems, + poly: { + allowIntersection: false, + }, + }, + }) + var editOnlyControl = new window.L.Control.Draw({ + draw: false, + edit: { + featureGroup: drawnItems, + poly: { + allowIntersection: false, + }, + }, + }) + this.map.addControl(drawControl) + + this.map.on('draw:created', async (e) => { + let layer = e.layer + let points = layer._latlngs[0] + drawnItems.addLayer(layer) + //disable draw tool + this.map.removeControl(drawControl) + this.map.addControl(editOnlyControl) + if (this.onSelecetMultPoints) { + this.onSelecetMultPoints(points) + } + }) + this.map.on('draw:edited', async (e) => { + let layers = e.layers._layers + let polygon = Object.values(layers)[0] + if (polygon) { + if (this.onSelecetMultPoints) { + this.onSelecetMultPoints(polygon._latlngs[0]) + } + } + }) + this.map.on('draw:deleted', async (e) => { + //enable draw tool if all polygons deleted + if (drawnItems.getLayers().length == 0) { + this.map.removeControl(editOnlyControl) + this.map.addControl(drawControl) + } + }) + //enable drawing mode which prevent user move when clicking on icon tree or group + this.map.on('draw:drawstart ', (e) => { + this.isDrawingMode = true + }) + this.map.on('draw:drawstop ', (e) => { + this.isDrawingMode = false + }) + this.map.on('draw:editstart ', (e) => { + this.isDrawingMode = true + }) + this.map.on('draw:editstop ', (e) => { + this.isDrawingMode = false + }) + } +} +export default DrawTool diff --git a/src/Map.js b/src/Map.js index 95d1667..6515544 100644 --- a/src/Map.js +++ b/src/Map.js @@ -24,6 +24,7 @@ import Alert from './Alert' import TileLoadingMonitor from './TileLoadingMonitor' import ButtonPanel from './ButtonPanel' import NearestTreeArrows from './NearestTreeArrows' +import DrawTool from './DrawTool' class MapError extends Error {} @@ -54,7 +55,7 @@ export default class Map { tileServerUrl: 'https://{s}.treetracker.org/tiles/', tileServerSubdomains: ['prod-k8s'], apiServerUrl: 'https://prod-k8s.treetracker.org/webmap/', - queryApiServerUrl: 'https://prod-k8s.treetracker.org/query', + queryApiServerUrl: 'http://localhost:3006', debug: false, moreEffect: true, filters: null, @@ -1460,40 +1461,10 @@ export default class Map { } async _loadEditor() { - //var map = L.map('map', {drawControl: true}).setView([51.505, -0.09], 13); - // L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { - // attribution: '© OpenStreetMap contributors' - // }).addTo(this.map); - // FeatureGroup is to store editable layers - var drawnItems = new window.L.FeatureGroup() - this.map.addLayer(drawnItems) - var drawControl = new window.L.Control.Draw({ - draw: { - marker: false, - polyline: false, - circlemarker: false, - circle: false, - polygon: { - allowIntersection: false, - }, - }, - edit: { - featureGroup: drawnItems, - poly: { - allowIntersection: false, - }, - }, - }) - var editOnlyControl = new window.L.Control.Draw({ - draw: false, - edit: { - featureGroup: drawnItems, - poly: { - allowIntersection: false, - }, - }, - }) - this.map.addControl(drawControl) + //create draw tool + this.drawTool = new DrawTool(this.map) + + //add panel to track how many selected var panel = window.L.control({ position: 'topright' }) panel.onAdd = function (map) { var div = window.L.DomUtil.create('div', 'info') @@ -1506,15 +1477,9 @@ export default class Map { return div } panel.addTo(this.map) - //using leaflet to draw a polygon, when finished, the polygon will be added to the map - this.map.on('draw:created', async (e) => { - let type = e.layerType, - layer = e.layer - let points = layer._latlngs[0] - drawnItems.addLayer(layer) - //disable draw tool - this.map.removeControl(drawControl) - this.map.addControl(editOnlyControl) + + //create event for select multiple trees event + const onSelectMultTrees = async (points) => { const result = await this._getTreesFromPoly(points) var total = result?.trees?.length || 0 document.getElementById('treeTotal').innerHTML = total @@ -1528,48 +1493,9 @@ export default class Map { result?.trees || [], ) } - }) - this.map.on('draw:edited', async (e) => { - let layers = e.layers._layers - let polygon = Object.values(layers)[0] - //if no polygon edited - if (polygon) { - const result = await this._getTreesFromPoly(polygon._latlngs[0]) - var total = result?.trees?.length || 0 - document.getElementById('treeTotal').innerHTML = total - if ( - this.events.listenerCount( - Map.REGISTERED_EVENTS.MULTIPLE_TREES_SELECTED, - ) > 0 - ) { - this.events.emit( - Map.REGISTERED_EVENTS.MULTIPLE_TREES_SELECTED, - result?.trees || [], - ) - } - } - }) - this.map.on('draw:deleted', async (e) => { - //enable draw tool if all polygons deleted - if (drawnItems.getLayers().length == 0) { - this.map.removeControl(editOnlyControl) - this.map.addControl(drawControl) - document.getElementById('treeTotal').innerHTML = 0 - } - }) - //enable drawing mode which prevent user move when clicking on icon tree or group - this.map.on('draw:drawstart ', (e) => { - this.isDrawingMode = true - }) - this.map.on('draw:drawstop ', (e) => { - this.isDrawingMode = false - }) - this.map.on('draw:editstart ', (e) => { - this.isDrawingMode = true - }) - this.map.on('draw:editstop ', (e) => { - this.isDrawingMode = false - }) + } + //add select multiple trees event to the draw tool + this.drawTool.onSelecetMultiplePoints(onSelectMultTrees) } clearSelection() { From 75c8ad23bd1e342e98caa94ef8a281975a8948f2 Mon Sep 17 00:00:00 2001 From: QuanGiap Date: Sat, 23 Mar 2024 16:05:06 -0700 Subject: [PATCH 6/6] fix: clean up code --- src/Map.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Map.js b/src/Map.js index 6515544..ef7fa05 100644 --- a/src/Map.js +++ b/src/Map.js @@ -55,7 +55,7 @@ export default class Map { tileServerUrl: 'https://{s}.treetracker.org/tiles/', tileServerSubdomains: ['prod-k8s'], apiServerUrl: 'https://prod-k8s.treetracker.org/webmap/', - queryApiServerUrl: 'http://localhost:3006', + queryApiServerUrl: 'https://prod-k8s.treetracker.org/query', debug: false, moreEffect: true, filters: null, @@ -78,9 +78,6 @@ export default class Map { // mount element this._mountDomElement = null - //check if in drawing mode - this.isDrawingMode = false - log.warn('map core version:', require('../package.json').version) // Deprecation warnings @@ -331,7 +328,7 @@ export default class Map { ) this.layerUtfGrid.on('click', (e) => { log.warn('click:', e) - if (e.data && !this.isDrawingMode) { + if (e.data && !this.drawTool.isDrawingMode) { this._clickMarker(Map._parseUtfData(e.data)) } })