Compare commits
13 Commits
42dea25fd1
...
77a3a5e288
Author | SHA1 | Date | |
---|---|---|---|
77a3a5e288 | |||
e44c578195 | |||
911983d250 | |||
c0a59bd30a | |||
4173a97e51 | |||
8eaf49fd54 | |||
7f583e73b0 | |||
f20031e2ea | |||
2da0ee24e4 | |||
4c39cee484 | |||
196063c23b | |||
f97b3b5185 | |||
95cf93d747 |
@ -1,2 +1,10 @@
|
|||||||
.env
|
.env
|
||||||
node_modules
|
node_modules
|
||||||
|
*/prisma
|
||||||
|
!common/prisma
|
||||||
|
*/node_modules
|
||||||
|
*/protos
|
||||||
|
!common/protos
|
||||||
|
*/Dockerfile
|
||||||
|
*/.dockerignore
|
||||||
|
webapp/frontend/node_modules
|
||||||
|
@ -12,7 +12,14 @@ jobs:
|
|||||||
run: docker login git.arinity.org -u matt -p ${{ secrets.DOCKER_PUSH_TOKEN }}
|
run: docker login git.arinity.org -u matt -p ${{ secrets.DOCKER_PUSH_TOKEN }}
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Build docker image
|
- name: Build web app image
|
||||||
run: docker build -t git.arinity.org/ctmesh/map:latest .
|
run: docker build -f webapp/Dockerfile -t git.arinity.org/ctmesh:map-web:latest .
|
||||||
- name: Push image
|
- name: Build mqtt listener image
|
||||||
run: docker push git.arinity.org/ctmesh/map:latest
|
run: docker build -f mqtt/Dockerfile -t git.arinity.org/ctmesh:map-mqtt:latest .
|
||||||
|
- name: Build cli image
|
||||||
|
run: docker build -f cli/Dockerfile -t git.arinity.org/ctmesh:map-cli:latest .
|
||||||
|
- name: Push images
|
||||||
|
run: |
|
||||||
|
docker push git.arinity.org/ctmesh:map-web:latest
|
||||||
|
docker push git.arinity.org/ctmesh/map-mqtt:latest
|
||||||
|
docker push git.arinity.org/ctmesh:map-cli:latest
|
||||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,4 +1,8 @@
|
|||||||
.idea/
|
.idea/
|
||||||
node_modules
|
node_modules
|
||||||
|
*/prisma
|
||||||
|
*/proto
|
||||||
|
*/protos
|
||||||
|
*/dist
|
||||||
# Keep environment variables out of version control
|
# Keep environment variables out of version control
|
||||||
.env
|
.env
|
||||||
|
10
Dockerfile
10
Dockerfile
@ -1,10 +0,0 @@
|
|||||||
FROM node:lts
|
|
||||||
|
|
||||||
# add project files to /app
|
|
||||||
ADD ./ /app
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# install node dependencies
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
EXPOSE 8080
|
|
12
cli/Dockerfile
Normal file
12
cli/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
FROM node:lts-alpine3.17
|
||||||
|
|
||||||
|
# add project files to /app
|
||||||
|
ADD ./cli /app
|
||||||
|
ADD ./common /app
|
||||||
|
ADD ./mqtt/utils /app/utils
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# install node dependencies
|
||||||
|
RUN npm install && npx prisma generate
|
||||||
|
|
||||||
|
ENTRYPOINT ["node", "index.js"]
|
18
cli/package.json
Normal file
18
cli/package.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "mqtt",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/client": "^5.11.0",
|
||||||
|
"command-line-args": "^5.2.1",
|
||||||
|
"command-line-usage": "^7.0.1",
|
||||||
|
"mqtt": "^5.11.0",
|
||||||
|
"protobufjs": "^7.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prisma": "^5.10.2"
|
||||||
|
}
|
||||||
|
}
|
8
common/entrypoint.sh
Executable file
8
common/entrypoint.sh
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Running migrations"
|
||||||
|
npx prisma migrate deploy
|
||||||
|
|
||||||
|
echo "Starting application"
|
||||||
|
node index.js "$@"
|
@ -2,28 +2,26 @@ services:
|
|||||||
# listens to mqtt packets and saves to database
|
# listens to mqtt packets and saves to database
|
||||||
meshtastic-mqtt:
|
meshtastic-mqtt:
|
||||||
container_name: meshtastic-mqtt
|
container_name: meshtastic-mqtt
|
||||||
image: git.arinity.org/ctmesh/map:latest
|
image: git.arinity.org/ctmesh/map-mqtt:latest
|
||||||
depends_on:
|
depends_on:
|
||||||
database:
|
database:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
command: /app/docker/mqtt.sh
|
command: "--mqtt-topic=msh/US/#"
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: "mysql://root:password@database:3306/meshtastic-map?connection_limit=100"
|
DATABASE_URL: "mysql://root:password@database:3306/meshtastic-map?connection_limit=100"
|
||||||
MQTT_OPTS: "--mqtt-broker-url=" # add any custom mqtt.js options here
|
|
||||||
|
|
||||||
# runs the web map ui
|
# runs the web map ui
|
||||||
meshtastic-map:
|
meshtastic-map:
|
||||||
container_name: meshtastic-map
|
container_name: meshtastic-map
|
||||||
image: git.arinity.org/ctmesh/map:latest
|
image: git.arinity.org/ctmesh/map-web:latest
|
||||||
depends_on:
|
depends_on:
|
||||||
database:
|
database:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
command: /app/docker/map.sh
|
command: "--port=8080"
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080/tcp
|
- 8080:8080/tcp
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: "mysql://root:password@database:3306/meshtastic-map?connection_limit=100"
|
DATABASE_URL: "mysql://root:password@database:3306/meshtastic-map?connection_limit=100"
|
||||||
MAP_OPTS: "" # add any custom index.js options here
|
|
||||||
|
|
||||||
# runs the database to store everything from mqtt
|
# runs the database to store everything from mqtt
|
||||||
database:
|
database:
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
echo "Running migrations"
|
|
||||||
npx prisma migrate dev
|
|
||||||
|
|
||||||
echo "Starting map ui"
|
|
||||||
exec node src/index.js ${MAP_OPTS}
|
|
@ -1,7 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
echo "Running migrations"
|
|
||||||
npx prisma migrate dev
|
|
||||||
|
|
||||||
echo "Starting mqtt listener"
|
|
||||||
exec node src/mqtt.js ${MQTT_OPTS}
|
|
10
donate.md
10
donate.md
@ -1,10 +0,0 @@
|
|||||||
# Donate
|
|
||||||
|
|
||||||
Thank you for considering donating, this helps support my work on this project 😁
|
|
||||||
|
|
||||||
## How can I donate?
|
|
||||||
|
|
||||||
- Bitcoin: bc1qy22smke8n4c54evdxmp7lpy9p0e6m9tavtlg2q
|
|
||||||
- Ethereum: 0xc64CFbA5D0BF7664158c5671F64d446395b3bF3D
|
|
||||||
- Buy me a Coffee: [https://ko-fi.com/liamcottle](https://ko-fi.com/liamcottle)
|
|
||||||
- Sponsor on GitHub: [https://github.com/sponsors/liamcottle](https://github.com/sponsors/liamcottle)
|
|
@ -1,39 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=meshtastic-map-mqtt
|
|
||||||
After=network.target
|
|
||||||
StartLimitIntervalSec=0
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
Restart=always
|
|
||||||
RestartSec=1
|
|
||||||
User=liamcottle
|
|
||||||
WorkingDirectory=/home/liamcottle/meshtastic-map
|
|
||||||
ExecStart=/usr/bin/env node /home/liamcottle/meshtastic-map/src/mqtt.js \
|
|
||||||
--mqtt-broker-url mqtt://127.0.0.1 \
|
|
||||||
--mqtt-username username \
|
|
||||||
--mqtt-password password \
|
|
||||||
--mqtt-client-id meshtastic.example.com \
|
|
||||||
--mqtt-topic 'msh/#' \
|
|
||||||
--collect-positions \
|
|
||||||
--collect-text-messages \
|
|
||||||
--collect-waypoints \
|
|
||||||
--ignore-direct-messages \
|
|
||||||
--purge-interval-seconds 60 \
|
|
||||||
--purge-nodes-unheard-for-seconds 604800 \
|
|
||||||
--purge-device-metrics-after-seconds 604800 \
|
|
||||||
--purge-environment-metrics-after-seconds 604800 \
|
|
||||||
--purge-map-reports-after-seconds 604800 \
|
|
||||||
--purge-neighbour-infos-after-seconds 604800 \
|
|
||||||
--purge-power-metrics-after-seconds 604800 \
|
|
||||||
--purge-positions-after-seconds 604800 \
|
|
||||||
--purge-service-envelopes-after-seconds 604800 \
|
|
||||||
--purge-text-messages-after-seconds 604800 \
|
|
||||||
--purge-traceroutes-after-seconds 604800 \
|
|
||||||
--purge-waypoints-after-seconds 604800 \
|
|
||||||
--forget-outdated-node-positions-after-seconds 604800 \
|
|
||||||
--drop-packets-not-ok-to-mqtt \
|
|
||||||
--old-firmware-position-precision 16
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
@ -1,15 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=meshtastic-map
|
|
||||||
After=network.target
|
|
||||||
StartLimitIntervalSec=0
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
Restart=always
|
|
||||||
RestartSec=1
|
|
||||||
User=liamcottle
|
|
||||||
WorkingDirectory=/home/liamcottle/meshtastic-map
|
|
||||||
ExecStart=/usr/bin/env node /home/liamcottle/meshtastic-map/src/index.js
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
11
mqtt/Dockerfile
Normal file
11
mqtt/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
FROM node:lts-alpine3.17
|
||||||
|
|
||||||
|
# add project files to /app
|
||||||
|
ADD ./mqtt /app
|
||||||
|
ADD ./common /app
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# install node dependencies
|
||||||
|
RUN npm install && npx prisma generate
|
||||||
|
|
||||||
|
ENTRYPOINT ["/app/entrypoint.sh"]
|
955
mqtt/package-lock.json
generated
Normal file
955
mqtt/package-lock.json
generated
Normal file
@ -0,0 +1,955 @@
|
|||||||
|
{
|
||||||
|
"name": "mqtt",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "mqtt",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/client": "^5.11.0",
|
||||||
|
"command-line-args": "^5.2.1",
|
||||||
|
"command-line-usage": "^7.0.1",
|
||||||
|
"mqtt": "^5.11.0",
|
||||||
|
"protobufjs": "^7.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prisma": "^5.10.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@babel/runtime": {
|
||||||
|
"version": "7.27.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
|
||||||
|
"integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"regenerator-runtime": "^0.14.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/client": {
|
||||||
|
"version": "5.22.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.22.0.tgz",
|
||||||
|
"integrity": "sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.13"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"prisma": "*"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"prisma": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/debug": {
|
||||||
|
"version": "5.22.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.22.0.tgz",
|
||||||
|
"integrity": "sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==",
|
||||||
|
"devOptional": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/engines": {
|
||||||
|
"version": "5.22.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.22.0.tgz",
|
||||||
|
"integrity": "sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA==",
|
||||||
|
"devOptional": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/debug": "5.22.0",
|
||||||
|
"@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2",
|
||||||
|
"@prisma/fetch-engine": "5.22.0",
|
||||||
|
"@prisma/get-platform": "5.22.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/engines-version": {
|
||||||
|
"version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2.tgz",
|
||||||
|
"integrity": "sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ==",
|
||||||
|
"devOptional": true,
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/fetch-engine": {
|
||||||
|
"version": "5.22.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.22.0.tgz",
|
||||||
|
"integrity": "sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA==",
|
||||||
|
"devOptional": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/debug": "5.22.0",
|
||||||
|
"@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2",
|
||||||
|
"@prisma/get-platform": "5.22.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@prisma/get-platform": {
|
||||||
|
"version": "5.22.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.22.0.tgz",
|
||||||
|
"integrity": "sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q==",
|
||||||
|
"devOptional": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/debug": "5.22.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@protobufjs/aspromise": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/@protobufjs/base64": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/@protobufjs/codegen": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/@protobufjs/eventemitter": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/@protobufjs/fetch": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"@protobufjs/aspromise": "^1.1.1",
|
||||||
|
"@protobufjs/inquire": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@protobufjs/float": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/@protobufjs/inquire": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/@protobufjs/path": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/@protobufjs/pool": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/@protobufjs/utf8": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "22.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz",
|
||||||
|
"integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~6.21.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/readable-stream": {
|
||||||
|
"version": "4.0.18",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.18.tgz",
|
||||||
|
"integrity": "sha512-21jK/1j+Wg+7jVw1xnSwy/2Q1VgVjWuFssbYGTREPUBeZ+rqVFl2udq0IkxzPC0ZhOzVceUbyIACFZKLqKEBlA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"safe-buffer": "~5.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/ws": {
|
||||||
|
"version": "8.18.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
|
||||||
|
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/abort-controller": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"event-target-shim": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ansi-styles": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/array-back": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/base64-js": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
|
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/bl": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bl/-/bl-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-ClDyJGQkc8ZtzdAAbAwBmhMSpwN/sC9HA8jxdYm6nVUbCfZbe2mgza4qh7AuEYyEPB/c4Kznf9s66bnsKMQDjw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/readable-stream": "^4.0.0",
|
||||||
|
"buffer": "^6.0.3",
|
||||||
|
"inherits": "^2.0.4",
|
||||||
|
"readable-stream": "^4.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/buffer": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
|
"ieee754": "^1.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/buffer-from": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/chalk": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/chalk-template": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "^4.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/chalk-template?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/command-line-args": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"array-back": "^3.1.0",
|
||||||
|
"find-replace": "^3.0.0",
|
||||||
|
"lodash.camelcase": "^4.3.0",
|
||||||
|
"typical": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/command-line-usage": {
|
||||||
|
"version": "7.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz",
|
||||||
|
"integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"array-back": "^6.2.2",
|
||||||
|
"chalk-template": "^0.4.0",
|
||||||
|
"table-layout": "^4.1.0",
|
||||||
|
"typical": "^7.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.20.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/command-line-usage/node_modules/array-back": {
|
||||||
|
"version": "6.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz",
|
||||||
|
"integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/command-line-usage/node_modules/typical": {
|
||||||
|
"version": "7.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz",
|
||||||
|
"integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/commist": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/concat-stream": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
|
||||||
|
"engines": [
|
||||||
|
"node >= 6.0"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer-from": "^1.0.0",
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"readable-stream": "^3.0.2",
|
||||||
|
"typedarray": "^0.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/concat-stream/node_modules/readable-stream": {
|
||||||
|
"version": "3.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||||
|
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/debug": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/event-target-shim": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/events": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fast-unique-numbers": {
|
||||||
|
"version": "8.0.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-8.0.13.tgz",
|
||||||
|
"integrity": "sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.23.8",
|
||||||
|
"tslib": "^2.6.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/find-replace": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"array-back": "^3.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/has-flag": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/help-me": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/ieee754": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/inherits": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/ip-address": {
|
||||||
|
"version": "9.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
|
||||||
|
"integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jsbn": "1.1.0",
|
||||||
|
"sprintf-js": "^1.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/js-sdsl": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/js-sdsl"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jsbn": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.camelcase": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/long": {
|
||||||
|
"version": "5.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/long/-/long-5.3.1.tgz",
|
||||||
|
"integrity": "sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/lru-cache": {
|
||||||
|
"version": "10.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||||
|
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/minimist": {
|
||||||
|
"version": "1.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||||
|
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mqtt": {
|
||||||
|
"version": "5.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.11.0.tgz",
|
||||||
|
"integrity": "sha512-VDqfADTNvohwcY02NgxPb7OojIeDrNQ1q62r/DcM+bnIWY8LBi3nMTvdEaFEp6Bu4ejBIpHjJVthUEgnvGLemA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/readable-stream": "^4.0.18",
|
||||||
|
"@types/ws": "^8.5.14",
|
||||||
|
"commist": "^3.2.0",
|
||||||
|
"concat-stream": "^2.0.0",
|
||||||
|
"debug": "^4.4.0",
|
||||||
|
"help-me": "^5.0.0",
|
||||||
|
"lru-cache": "^10.4.3",
|
||||||
|
"minimist": "^1.2.8",
|
||||||
|
"mqtt-packet": "^9.0.2",
|
||||||
|
"number-allocator": "^1.0.14",
|
||||||
|
"readable-stream": "^4.7.0",
|
||||||
|
"reinterval": "^1.1.0",
|
||||||
|
"rfdc": "^1.4.1",
|
||||||
|
"socks": "^2.8.3",
|
||||||
|
"split2": "^4.2.0",
|
||||||
|
"worker-timers": "^7.1.8",
|
||||||
|
"ws": "^8.18.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"mqtt": "build/bin/mqtt.js",
|
||||||
|
"mqtt_pub": "build/bin/pub.js",
|
||||||
|
"mqtt_sub": "build/bin/sub.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mqtt-packet": {
|
||||||
|
"version": "9.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.2.tgz",
|
||||||
|
"integrity": "sha512-MvIY0B8/qjq7bKxdN1eD+nrljoeaai+qjLJgfRn3TiMuz0pamsIWY2bFODPZMSNmabsLANXsLl4EMoWvlaTZWA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"bl": "^6.0.8",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"process-nextick-args": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ms": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/number-allocator": {
|
||||||
|
"version": "1.0.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz",
|
||||||
|
"integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.3.1",
|
||||||
|
"js-sdsl": "4.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/prisma": {
|
||||||
|
"version": "5.22.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prisma/-/prisma-5.22.0.tgz",
|
||||||
|
"integrity": "sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A==",
|
||||||
|
"devOptional": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/engines": "5.22.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"prisma": "build/index.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.13"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"fsevents": "2.3.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/process": {
|
||||||
|
"version": "0.11.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||||
|
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/process-nextick-args": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/protobufjs": {
|
||||||
|
"version": "7.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.0.tgz",
|
||||||
|
"integrity": "sha512-Z2E/kOY1QjoMlCytmexzYfDm/w5fKAiRwpSzGtdnXW1zC88Z2yXazHHrOtwCzn+7wSxyE8PYM4rvVcMphF9sOA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"@protobufjs/aspromise": "^1.1.2",
|
||||||
|
"@protobufjs/base64": "^1.1.2",
|
||||||
|
"@protobufjs/codegen": "^2.0.4",
|
||||||
|
"@protobufjs/eventemitter": "^1.1.0",
|
||||||
|
"@protobufjs/fetch": "^1.1.0",
|
||||||
|
"@protobufjs/float": "^1.0.2",
|
||||||
|
"@protobufjs/inquire": "^1.1.0",
|
||||||
|
"@protobufjs/path": "^1.1.2",
|
||||||
|
"@protobufjs/pool": "^1.1.0",
|
||||||
|
"@protobufjs/utf8": "^1.1.0",
|
||||||
|
"@types/node": ">=13.7.0",
|
||||||
|
"long": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/readable-stream": {
|
||||||
|
"version": "4.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
|
||||||
|
"integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"abort-controller": "^3.0.0",
|
||||||
|
"buffer": "^6.0.3",
|
||||||
|
"events": "^3.3.0",
|
||||||
|
"process": "^0.11.10",
|
||||||
|
"string_decoder": "^1.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/regenerator-runtime": {
|
||||||
|
"version": "0.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||||
|
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/reinterval": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/rfdc": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/smart-buffer": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6.0.0",
|
||||||
|
"npm": ">= 3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/socks": {
|
||||||
|
"version": "2.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz",
|
||||||
|
"integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ip-address": "^9.0.5",
|
||||||
|
"smart-buffer": "^4.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0",
|
||||||
|
"npm": ">= 3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/split2": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sprintf-js": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/string_decoder": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/string_decoder/node_modules/safe-buffer": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/table-layout": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"array-back": "^6.2.2",
|
||||||
|
"wordwrapjs": "^5.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/table-layout/node_modules/array-back": {
|
||||||
|
"version": "6.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz",
|
||||||
|
"integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
|
"node_modules/typedarray": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||||
|
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/typical": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "6.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||||
|
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/util-deprecate": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/wordwrapjs": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-JNjcULU2e4KJwUNv6CHgI46UvDGitb6dGryHajXTDiLgg1/RiGoPSDw4kZfYnwGtEXf2ZMeIewDQgFGzkCB2Sg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/worker-timers": {
|
||||||
|
"version": "7.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-7.1.8.tgz",
|
||||||
|
"integrity": "sha512-R54psRKYVLuzff7c1OTFcq/4Hue5Vlz4bFtNEIarpSiCYhpifHU3aIQI29S84o1j87ePCYqbmEJPqwBTf+3sfw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.24.5",
|
||||||
|
"tslib": "^2.6.2",
|
||||||
|
"worker-timers-broker": "^6.1.8",
|
||||||
|
"worker-timers-worker": "^7.0.71"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/worker-timers-broker": {
|
||||||
|
"version": "6.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-6.1.8.tgz",
|
||||||
|
"integrity": "sha512-FUCJu9jlK3A8WqLTKXM9E6kAmI/dR1vAJ8dHYLMisLNB/n3GuaFIjJ7pn16ZcD1zCOf7P6H62lWIEBi+yz/zQQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.24.5",
|
||||||
|
"fast-unique-numbers": "^8.0.13",
|
||||||
|
"tslib": "^2.6.2",
|
||||||
|
"worker-timers-worker": "^7.0.71"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/worker-timers-worker": {
|
||||||
|
"version": "7.0.71",
|
||||||
|
"resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-7.0.71.tgz",
|
||||||
|
"integrity": "sha512-ks/5YKwZsto1c2vmljroppOKCivB/ma97g9y77MAAz2TBBjPPgpoOiS1qYQKIgvGTr2QYPT3XhJWIB6Rj2MVPQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.24.5",
|
||||||
|
"tslib": "^2.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ws": {
|
||||||
|
"version": "8.18.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz",
|
||||||
|
"integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
mqtt/package.json
Normal file
18
mqtt/package.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "mqtt",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/client": "^5.11.0",
|
||||||
|
"command-line-args": "^5.2.1",
|
||||||
|
"command-line-usage": "^7.0.1",
|
||||||
|
"mqtt": "^5.11.0",
|
||||||
|
"protobufjs": "^7.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prisma": "^5.10.2"
|
||||||
|
}
|
||||||
|
}
|
5057
package-lock.json
generated
5057
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
Before Width: | Height: | Size: 270 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,7 +0,0 @@
|
|||||||
/*!
|
|
||||||
* chartjs-adapter-moment v1.0.1
|
|
||||||
* https://www.chartjs.org
|
|
||||||
* (c) 2022 chartjs-adapter-moment Contributors
|
|
||||||
* Released under the MIT license
|
|
||||||
*/
|
|
||||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("moment"),require("chart.js")):"function"==typeof define&&define.amd?define(["moment","chart.js"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).moment,e.Chart)}(this,(function(e,t){"use strict";function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var f=n(e);const a={datetime:"MMM D, YYYY, h:mm:ss a",millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm a",hour:"hA",day:"MMM D",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"};t._adapters._date.override("function"==typeof f.default?{_id:"moment",formats:function(){return a},parse:function(e,t){return"string"==typeof e&&"string"==typeof t?e=f.default(e,t):e instanceof f.default||(e=f.default(e)),e.isValid()?e.valueOf():null},format:function(e,t){return f.default(e).format(t)},add:function(e,t,n){return f.default(e).add(t,n).valueOf()},diff:function(e,t,n){return f.default(e).diff(f.default(t),n)},startOf:function(e,t,n){return e=f.default(e),"isoWeek"===t?(n=Math.trunc(Math.min(Math.max(0,n),6)),e.isoWeekday(n).startOf("day").valueOf()):e.startOf(t).valueOf()},endOf:function(e,t){return f.default(e).endOf(t).valueOf()}}:{})}));
|
|
@ -1,691 +0,0 @@
|
|||||||
function modulus(i, n) {
|
|
||||||
return ((i % n) + n) % n;
|
|
||||||
}
|
|
||||||
|
|
||||||
function definedProps(obj) {
|
|
||||||
return Object.fromEntries(
|
|
||||||
Object.entries(obj).filter(([k, v]) => v !== undefined)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not a string is in the format '<number>m'
|
|
||||||
* @param {string} value
|
|
||||||
* @returns Boolean
|
|
||||||
*/
|
|
||||||
function isInMeters(value) {
|
|
||||||
return (
|
|
||||||
value
|
|
||||||
.toString()
|
|
||||||
.trim()
|
|
||||||
.slice(value.toString().length - 1, value.toString().length) === 'm'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not a string is in the format '<number>%'
|
|
||||||
* @param {string} value
|
|
||||||
* @returns Boolean
|
|
||||||
*/
|
|
||||||
function isInPercent(value) {
|
|
||||||
return (
|
|
||||||
value
|
|
||||||
.toString()
|
|
||||||
.trim()
|
|
||||||
.slice(value.toString().length - 1, value.toString().length) === '%'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not a string is in the format '<number>px'
|
|
||||||
* @param {string} value
|
|
||||||
* @returns Boolean
|
|
||||||
*/
|
|
||||||
function isInPixels(value) {
|
|
||||||
return (
|
|
||||||
value
|
|
||||||
.toString()
|
|
||||||
.trim()
|
|
||||||
.slice(value.toString().length - 2, value.toString().length) === 'px'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function pixelsToMeters(pixels, map) {
|
|
||||||
let refPoint1 = map.getCenter();
|
|
||||||
let xy1 = map.latLngToLayerPoint(refPoint1);
|
|
||||||
let xy2 = {
|
|
||||||
x: xy1.x + Number(pixels),
|
|
||||||
y: xy1.y,
|
|
||||||
};
|
|
||||||
let refPoint2 = map.layerPointToLatLng(xy2);
|
|
||||||
let derivedMeters = map.distance(refPoint1, refPoint2);
|
|
||||||
return derivedMeters;
|
|
||||||
}
|
|
||||||
|
|
||||||
L.Polyline.include({
|
|
||||||
/**
|
|
||||||
* Adds arrowheads to an L.polyline
|
|
||||||
* @param {object} options The options for the arrowhead. See documentation for details
|
|
||||||
* @returns The L.polyline instance that they arrowheads are attached to
|
|
||||||
*/
|
|
||||||
arrowheads: function (options = {}) {
|
|
||||||
// Merge user input options with default options:
|
|
||||||
const defaults = {
|
|
||||||
yawn: 60,
|
|
||||||
size: '15%',
|
|
||||||
frequency: 'allvertices',
|
|
||||||
proportionalToTotal: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.options.noClip = true;
|
|
||||||
|
|
||||||
let actualOptions = Object.assign({}, defaults, options);
|
|
||||||
this._arrowheadOptions = actualOptions;
|
|
||||||
|
|
||||||
this._hatsApplied = true;
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
buildVectorHats: function (options) {
|
|
||||||
// Reset variables from previous this._update()
|
|
||||||
if (this._arrowheads) {
|
|
||||||
this._arrowheads.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._ghosts) {
|
|
||||||
this._ghosts.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------- //
|
|
||||||
// ------------ FILTER THE OPTIONS ----------------------- //
|
|
||||||
/*
|
|
||||||
* The next 3 lines folds the options of the parent polyline into the default options for all polylines
|
|
||||||
* The options for the arrowhead are then folded in as well
|
|
||||||
* All options defined in parent polyline will be inherited by the arrowhead, unless otherwise specified in the arrowhead(options) call
|
|
||||||
*/
|
|
||||||
|
|
||||||
let defaultOptionsOfParent = Object.getPrototypeOf(
|
|
||||||
Object.getPrototypeOf(this.options)
|
|
||||||
);
|
|
||||||
|
|
||||||
// merge default options of parent polyline (this.options's prototype's prototype) with options passed to parent polyline (this.options).
|
|
||||||
let parentOptions = Object.assign({}, defaultOptionsOfParent, this.options);
|
|
||||||
|
|
||||||
// now merge in the options the user has put in the arrowhead call
|
|
||||||
let hatOptions = Object.assign({}, parentOptions, options);
|
|
||||||
|
|
||||||
// ...with a few exceptions:
|
|
||||||
hatOptions.smoothFactor = 1;
|
|
||||||
hatOptions.fillOpacity = 1;
|
|
||||||
hatOptions.fill = options.fill ? true : false;
|
|
||||||
hatOptions.interactive = false;
|
|
||||||
|
|
||||||
// ------------ FILTER THE OPTIONS END -------------------- //
|
|
||||||
// --------------------------------------------------------- //
|
|
||||||
|
|
||||||
// --------------------------------------------------------- //
|
|
||||||
// ------ LOOP THROUGH EACH POLYLINE SEGMENT --------------- //
|
|
||||||
// ------ TO CALCULATE HAT SIZES AND CAPTURE IN ARRAY ------ //
|
|
||||||
|
|
||||||
let size = options.size.toString(); // stringify if its a number
|
|
||||||
let allhats = []; // empty array to receive hat polylines
|
|
||||||
const { frequency, offsets } = options;
|
|
||||||
|
|
||||||
if (offsets?.start || offsets?.end) {
|
|
||||||
this._buildGhosts({ start: offsets.start, end: offsets.end });
|
|
||||||
}
|
|
||||||
|
|
||||||
const lineToTrace = this._ghosts || this;
|
|
||||||
|
|
||||||
lineToTrace._parts.forEach((peice, index) => {
|
|
||||||
// Immutable variables for each peice
|
|
||||||
const latlngs = peice.map((point) => this._map.layerPointToLatLng(point));
|
|
||||||
|
|
||||||
const totalLength = (() => {
|
|
||||||
let total = 0;
|
|
||||||
for (var i = 0; i < peice.length - 1; i++) {
|
|
||||||
total += this._map.distance(latlngs[i], latlngs[i + 1]);
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
})();
|
|
||||||
|
|
||||||
// TBD by options if tree below
|
|
||||||
let derivedLatLngs;
|
|
||||||
let derivedBearings;
|
|
||||||
let spacing;
|
|
||||||
let noOfPoints;
|
|
||||||
|
|
||||||
// Determining latlng and bearing arrays based on frequency choice:
|
|
||||||
if (!isNaN(frequency)) {
|
|
||||||
spacing = 1 / frequency;
|
|
||||||
noOfPoints = frequency;
|
|
||||||
} else if (isInPercent(frequency)) {
|
|
||||||
console.error(
|
|
||||||
'Error: arrowhead frequency option cannot be given in percent. Try another unit.'
|
|
||||||
);
|
|
||||||
} else if (isInMeters(frequency)) {
|
|
||||||
spacing = frequency.slice(0, frequency.length - 1) / totalLength;
|
|
||||||
noOfPoints = 1 / spacing;
|
|
||||||
// round things out for more even spacing:
|
|
||||||
noOfPoints = Math.floor(noOfPoints);
|
|
||||||
spacing = 1 / noOfPoints;
|
|
||||||
} else if (isInPixels(frequency)) {
|
|
||||||
spacing = (() => {
|
|
||||||
let chosenFrequency = frequency.slice(0, frequency.length - 2);
|
|
||||||
let derivedMeters = pixelsToMeters(chosenFrequency, this._map);
|
|
||||||
return derivedMeters / totalLength;
|
|
||||||
})();
|
|
||||||
|
|
||||||
noOfPoints = 1 / spacing;
|
|
||||||
|
|
||||||
// round things out for more even spacing:
|
|
||||||
noOfPoints = Math.floor(noOfPoints);
|
|
||||||
spacing = 1 / noOfPoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.frequency === 'allvertices') {
|
|
||||||
derivedBearings = (() => {
|
|
||||||
let bearings = [];
|
|
||||||
for (var i = 1; i < latlngs.length; i++) {
|
|
||||||
let bearing =
|
|
||||||
L.GeometryUtil.angle(
|
|
||||||
this._map,
|
|
||||||
latlngs[modulus(i - 1, latlngs.length)],
|
|
||||||
latlngs[i]
|
|
||||||
) + 180;
|
|
||||||
bearings.push(bearing);
|
|
||||||
}
|
|
||||||
return bearings;
|
|
||||||
})();
|
|
||||||
|
|
||||||
derivedLatLngs = latlngs;
|
|
||||||
derivedLatLngs.shift();
|
|
||||||
} else if (options.frequency === 'endonly' && latlngs.length >= 2) {
|
|
||||||
derivedLatLngs = [latlngs[latlngs.length - 1]];
|
|
||||||
|
|
||||||
derivedBearings = [
|
|
||||||
L.GeometryUtil.angle(
|
|
||||||
this._map,
|
|
||||||
latlngs[latlngs.length - 2],
|
|
||||||
latlngs[latlngs.length - 1]
|
|
||||||
) + 180,
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
derivedLatLngs = [];
|
|
||||||
let interpolatedPoints = [];
|
|
||||||
for (var i = 0; i < noOfPoints; i++) {
|
|
||||||
let interpolatedPoint = L.GeometryUtil.interpolateOnLine(
|
|
||||||
this._map,
|
|
||||||
latlngs,
|
|
||||||
spacing * (i + 1)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (interpolatedPoint) {
|
|
||||||
interpolatedPoints.push(interpolatedPoint);
|
|
||||||
derivedLatLngs.push(interpolatedPoint.latLng);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
derivedBearings = (() => {
|
|
||||||
let bearings = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < interpolatedPoints.length; i++) {
|
|
||||||
let bearing = L.GeometryUtil.angle(
|
|
||||||
this._map,
|
|
||||||
latlngs[interpolatedPoints[i].predecessor + 1],
|
|
||||||
latlngs[interpolatedPoints[i].predecessor]
|
|
||||||
);
|
|
||||||
bearings.push(bearing);
|
|
||||||
}
|
|
||||||
return bearings;
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
|
|
||||||
let hats = [];
|
|
||||||
|
|
||||||
// Function to build hats based on index and a given hatsize in meters
|
|
||||||
const pushHats = (size, localHatOptions = {}) => {
|
|
||||||
let yawn = localHatOptions.yawn ?? options.yawn;
|
|
||||||
|
|
||||||
let leftWingPoint = L.GeometryUtil.destination(
|
|
||||||
derivedLatLngs[i],
|
|
||||||
derivedBearings[i] - yawn / 2,
|
|
||||||
size
|
|
||||||
);
|
|
||||||
|
|
||||||
let rightWingPoint = L.GeometryUtil.destination(
|
|
||||||
derivedLatLngs[i],
|
|
||||||
derivedBearings[i] + yawn / 2,
|
|
||||||
size
|
|
||||||
);
|
|
||||||
|
|
||||||
let hatPoints = [
|
|
||||||
[leftWingPoint.lat, leftWingPoint.lng],
|
|
||||||
[derivedLatLngs[i].lat, derivedLatLngs[i].lng],
|
|
||||||
[rightWingPoint.lat, rightWingPoint.lng],
|
|
||||||
];
|
|
||||||
|
|
||||||
let hat = options.fill
|
|
||||||
? L.polygon(hatPoints, { ...hatOptions, ...localHatOptions })
|
|
||||||
: L.polyline(hatPoints, { ...hatOptions, ...localHatOptions });
|
|
||||||
|
|
||||||
hats.push(hat);
|
|
||||||
}; // pushHats()
|
|
||||||
|
|
||||||
// Function to build hats based on pixel input
|
|
||||||
const pushHatsFromPixels = (size, localHatOptions = {}) => {
|
|
||||||
let sizePixels = size.slice(0, size.length - 2);
|
|
||||||
let yawn = localHatOptions.yawn ?? options.yawn;
|
|
||||||
|
|
||||||
let derivedXY = this._map.latLngToLayerPoint(derivedLatLngs[i]);
|
|
||||||
|
|
||||||
let bearing = derivedBearings[i];
|
|
||||||
|
|
||||||
let thetaLeft = (180 - bearing - yawn / 2) * (Math.PI / 180),
|
|
||||||
thetaRight = (180 - bearing + yawn / 2) * (Math.PI / 180);
|
|
||||||
|
|
||||||
let dxLeft = sizePixels * Math.sin(thetaLeft),
|
|
||||||
dyLeft = sizePixels * Math.cos(thetaLeft),
|
|
||||||
dxRight = sizePixels * Math.sin(thetaRight),
|
|
||||||
dyRight = sizePixels * Math.cos(thetaRight);
|
|
||||||
|
|
||||||
let leftWingXY = {
|
|
||||||
x: derivedXY.x + dxLeft,
|
|
||||||
y: derivedXY.y + dyLeft,
|
|
||||||
};
|
|
||||||
let rightWingXY = {
|
|
||||||
x: derivedXY.x + dxRight,
|
|
||||||
y: derivedXY.y + dyRight,
|
|
||||||
};
|
|
||||||
|
|
||||||
let leftWingPoint = this._map.layerPointToLatLng(leftWingXY),
|
|
||||||
rightWingPoint = this._map.layerPointToLatLng(rightWingXY);
|
|
||||||
|
|
||||||
let hatPoints = [
|
|
||||||
[leftWingPoint.lat, leftWingPoint.lng],
|
|
||||||
[derivedLatLngs[i].lat, derivedLatLngs[i].lng],
|
|
||||||
[rightWingPoint.lat, rightWingPoint.lng],
|
|
||||||
];
|
|
||||||
|
|
||||||
let hat = options.fill
|
|
||||||
? L.polygon(hatPoints, { ...hatOptions, ...localHatOptions })
|
|
||||||
: L.polyline(hatPoints, { ...hatOptions, ...localHatOptions });
|
|
||||||
|
|
||||||
hats.push(hat);
|
|
||||||
}; // pushHatsFromPixels()
|
|
||||||
|
|
||||||
// ------- LOOP THROUGH POINTS IN EACH SEGMENT ---------- //
|
|
||||||
for (var i = 0; i < derivedLatLngs.length; i++) {
|
|
||||||
let { perArrowheadOptions, ...globalOptions } = options;
|
|
||||||
|
|
||||||
perArrowheadOptions = perArrowheadOptions ? perArrowheadOptions(i) : {};
|
|
||||||
perArrowheadOptions = Object.assign(
|
|
||||||
globalOptions,
|
|
||||||
definedProps(perArrowheadOptions)
|
|
||||||
);
|
|
||||||
|
|
||||||
size = perArrowheadOptions.size ?? size;
|
|
||||||
|
|
||||||
// ---- If size is chosen in meters -------------------------
|
|
||||||
if (isInMeters(size)) {
|
|
||||||
let hatSize = size.slice(0, size.length - 1);
|
|
||||||
pushHats(hatSize, perArrowheadOptions);
|
|
||||||
|
|
||||||
// ---- If size is chosen in percent ------------------------
|
|
||||||
} else if (isInPercent(size)) {
|
|
||||||
let sizePercent = size.slice(0, size.length - 1);
|
|
||||||
let hatSize = (() => {
|
|
||||||
if (
|
|
||||||
options.frequency === 'endonly' &&
|
|
||||||
options.proportionalToTotal
|
|
||||||
) {
|
|
||||||
return (totalLength * sizePercent) / 100;
|
|
||||||
} else {
|
|
||||||
let averageDistance = totalLength / (peice.length - 1);
|
|
||||||
return (averageDistance * sizePercent) / 100;
|
|
||||||
}
|
|
||||||
})(); // hatsize calculation
|
|
||||||
|
|
||||||
pushHats(hatSize, perArrowheadOptions);
|
|
||||||
|
|
||||||
// ---- If size is chosen in pixels --------------------------
|
|
||||||
} else if (isInPixels(size)) {
|
|
||||||
pushHatsFromPixels(options.size, perArrowheadOptions);
|
|
||||||
|
|
||||||
// ---- If size unit is not given -----------------------------
|
|
||||||
} else {
|
|
||||||
console.error(
|
|
||||||
'Error: Arrowhead size unit not defined. Check your arrowhead options.'
|
|
||||||
);
|
|
||||||
} // if else block for Size
|
|
||||||
} // for loop for each point witin a peice
|
|
||||||
|
|
||||||
allhats.push(...hats);
|
|
||||||
}); // forEach peice
|
|
||||||
|
|
||||||
// --------- LOOP THROUGH EACH POLYLINE END ---------------- //
|
|
||||||
// --------------------------------------------------------- //
|
|
||||||
|
|
||||||
let arrowheads = L.layerGroup(allhats);
|
|
||||||
this._arrowheads = arrowheads;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
getArrowheads: function () {
|
|
||||||
if (this._arrowheads) {
|
|
||||||
return this._arrowheads;
|
|
||||||
} else {
|
|
||||||
return console.error(
|
|
||||||
`Error: You tried to call '.getArrowheads() on a shape that does not have a arrowhead. Use '.arrowheads()' to add a arrowheads before trying to call '.getArrowheads()'`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds ghost polylines that are clipped versions of the polylines based on the offsets
|
|
||||||
* If offsets are used, arrowheads are drawn from 'this._ghosts' rather than 'this'
|
|
||||||
*/
|
|
||||||
_buildGhosts: function ({ start, end }) {
|
|
||||||
if (start || end) {
|
|
||||||
let latlngs = this.getLatLngs();
|
|
||||||
|
|
||||||
latlngs = Array.isArray(latlngs[0]) ? latlngs : [latlngs];
|
|
||||||
|
|
||||||
const newLatLngs = latlngs.map((segment) => {
|
|
||||||
// Get total distance of original latlngs
|
|
||||||
const totalLength = (() => {
|
|
||||||
let total = 0;
|
|
||||||
for (var i = 0; i < segment.length - 1; i++) {
|
|
||||||
total += this._map.distance(segment[i], segment[i + 1]);
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Modify latlngs to end at interpolated point
|
|
||||||
if (start) {
|
|
||||||
let endOffsetInMeters = (() => {
|
|
||||||
if (isInMeters(start)) {
|
|
||||||
return Number(start.slice(0, start.length - 1));
|
|
||||||
} else if (isInPixels(start)) {
|
|
||||||
let pixels = Number(start.slice(0, start.length - 2));
|
|
||||||
return pixelsToMeters(pixels, this._map);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
let newStart = L.GeometryUtil.interpolateOnLine(
|
|
||||||
this._map,
|
|
||||||
segment,
|
|
||||||
endOffsetInMeters / totalLength
|
|
||||||
);
|
|
||||||
|
|
||||||
segment = segment.slice(
|
|
||||||
newStart.predecessor === -1 ? 1 : newStart.predecessor + 1,
|
|
||||||
segment.length
|
|
||||||
);
|
|
||||||
segment.unshift(newStart.latLng);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end) {
|
|
||||||
let endOffsetInMeters = (() => {
|
|
||||||
if (isInMeters(end)) {
|
|
||||||
return Number(end.slice(0, end.length - 1));
|
|
||||||
} else if (isInPixels(end)) {
|
|
||||||
let pixels = Number(end.slice(0, end.length - 2));
|
|
||||||
return pixelsToMeters(pixels, this._map);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
let newEnd = L.GeometryUtil.interpolateOnLine(
|
|
||||||
this._map,
|
|
||||||
segment,
|
|
||||||
(totalLength - endOffsetInMeters) / totalLength
|
|
||||||
);
|
|
||||||
|
|
||||||
segment = segment.slice(0, newEnd.predecessor + 1);
|
|
||||||
segment.push(newEnd.latLng);
|
|
||||||
}
|
|
||||||
|
|
||||||
return segment;
|
|
||||||
});
|
|
||||||
|
|
||||||
this._ghosts = L.polyline(newLatLngs, {
|
|
||||||
...this.options,
|
|
||||||
color: 'rgba(0,0,0,0)',
|
|
||||||
stroke: 0,
|
|
||||||
smoothFactor: 0,
|
|
||||||
interactive: false,
|
|
||||||
});
|
|
||||||
this._ghosts.addTo(this._map);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
deleteArrowheads: function () {
|
|
||||||
if (this._arrowheads) {
|
|
||||||
this._arrowheads.remove();
|
|
||||||
delete this._arrowheads;
|
|
||||||
delete this._arrowheadOptions;
|
|
||||||
this._hatsApplied = false;
|
|
||||||
}
|
|
||||||
if (this._ghosts) {
|
|
||||||
this._ghosts.remove();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_update: function () {
|
|
||||||
if (!this._map) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._clipPoints();
|
|
||||||
this._simplifyPoints();
|
|
||||||
this._updatePath();
|
|
||||||
|
|
||||||
if (this._hatsApplied) {
|
|
||||||
this.buildVectorHats(this._arrowheadOptions);
|
|
||||||
this._map.addLayer(this._arrowheads);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
remove: function () {
|
|
||||||
if (this._arrowheads) {
|
|
||||||
this._arrowheads.remove();
|
|
||||||
}
|
|
||||||
if (this._ghosts) {
|
|
||||||
this._ghosts.remove();
|
|
||||||
}
|
|
||||||
return this.removeFrom(this._map || this._mapToAdd);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
L.LayerGroup.include({
|
|
||||||
removeLayer: function (layer) {
|
|
||||||
var id = layer in this._layers ? layer : this.getLayerId(layer);
|
|
||||||
|
|
||||||
if (this._map && this._layers[id]) {
|
|
||||||
if (this._layers[id]._arrowheads) {
|
|
||||||
this._layers[id]._arrowheads.remove();
|
|
||||||
}
|
|
||||||
this._map.removeLayer(this._layers[id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete this._layers[id];
|
|
||||||
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
onRemove: function (map, layer) {
|
|
||||||
for (var layer in this._layers) {
|
|
||||||
if (this._layers[layer]) {
|
|
||||||
this._layers[layer].remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.eachLayer(map.removeLayer, map);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
L.Map.include({
|
|
||||||
removeLayer: function (layer) {
|
|
||||||
var id = L.Util.stamp(layer);
|
|
||||||
|
|
||||||
if (layer._arrowheads) {
|
|
||||||
layer._arrowheads.remove();
|
|
||||||
}
|
|
||||||
if (layer._ghosts) {
|
|
||||||
layer._ghosts.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._layers[id]) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._loaded) {
|
|
||||||
layer.onRemove(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (layer.getAttribution && this.attributionControl) {
|
|
||||||
this.attributionControl.removeAttribution(layer.getAttribution());
|
|
||||||
}
|
|
||||||
|
|
||||||
delete this._layers[id];
|
|
||||||
|
|
||||||
if (this._loaded) {
|
|
||||||
this.fire('layerremove', { layer: layer });
|
|
||||||
layer.fire('remove');
|
|
||||||
}
|
|
||||||
|
|
||||||
layer._map = layer._mapToAdd = null;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
L.GeoJSON.include({
|
|
||||||
geometryToLayer: function (geojson, options) {
|
|
||||||
var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,
|
|
||||||
coords = geometry ? geometry.coordinates : null,
|
|
||||||
layers = [],
|
|
||||||
pointToLayer = options && options.pointToLayer,
|
|
||||||
_coordsToLatLng =
|
|
||||||
(options && options.coordsToLatLng) || L.GeoJSON.coordsToLatLng,
|
|
||||||
latlng,
|
|
||||||
latlngs,
|
|
||||||
i,
|
|
||||||
len;
|
|
||||||
|
|
||||||
if (!coords && !geometry) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (geometry.type) {
|
|
||||||
case 'Point':
|
|
||||||
latlng = _coordsToLatLng(coords);
|
|
||||||
return this._pointToLayer(pointToLayer, geojson, latlng, options);
|
|
||||||
|
|
||||||
case 'MultiPoint':
|
|
||||||
for (i = 0, len = coords.length; i < len; i++) {
|
|
||||||
latlng = _coordsToLatLng(coords[i]);
|
|
||||||
layers.push(
|
|
||||||
this._pointToLayer(pointToLayer, geojson, latlng, options)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return new L.FeatureGroup(layers);
|
|
||||||
|
|
||||||
case 'LineString':
|
|
||||||
case 'MultiLineString':
|
|
||||||
latlngs = L.GeoJSON.coordsToLatLngs(
|
|
||||||
coords,
|
|
||||||
geometry.type === 'LineString' ? 0 : 1,
|
|
||||||
_coordsToLatLng
|
|
||||||
);
|
|
||||||
var polyline = new L.Polyline(latlngs, options);
|
|
||||||
if (options.arrowheads) {
|
|
||||||
polyline.arrowheads(options.arrowheads);
|
|
||||||
}
|
|
||||||
return polyline;
|
|
||||||
|
|
||||||
case 'Polygon':
|
|
||||||
case 'MultiPolygon':
|
|
||||||
latlngs = L.GeoJSON.coordsToLatLngs(
|
|
||||||
coords,
|
|
||||||
geometry.type === 'Polygon' ? 1 : 2,
|
|
||||||
_coordsToLatLng
|
|
||||||
);
|
|
||||||
return new L.Polygon(latlngs, options);
|
|
||||||
|
|
||||||
case 'GeometryCollection':
|
|
||||||
for (i = 0, len = geometry.geometries.length; i < len; i++) {
|
|
||||||
var layer = this.geometryToLayer(
|
|
||||||
{
|
|
||||||
geometry: geometry.geometries[i],
|
|
||||||
type: 'Feature',
|
|
||||||
properties: geojson.properties,
|
|
||||||
},
|
|
||||||
options
|
|
||||||
);
|
|
||||||
|
|
||||||
if (layer) {
|
|
||||||
layers.push(layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new L.FeatureGroup(layers);
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error('Invalid GeoJSON object.');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
addData: function (geojson) {
|
|
||||||
var features = L.Util.isArray(geojson) ? geojson : geojson.features,
|
|
||||||
i,
|
|
||||||
len,
|
|
||||||
feature;
|
|
||||||
|
|
||||||
if (features) {
|
|
||||||
for (i = 0, len = features.length; i < len; i++) {
|
|
||||||
// only add this if geometry or geometries are set and not null
|
|
||||||
feature = features[i];
|
|
||||||
if (
|
|
||||||
feature.geometries ||
|
|
||||||
feature.geometry ||
|
|
||||||
feature.features ||
|
|
||||||
feature.coordinates
|
|
||||||
) {
|
|
||||||
this.addData(feature);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
var options = this.options;
|
|
||||||
|
|
||||||
if (options.filter && !options.filter(geojson)) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
var layer = this.geometryToLayer(geojson, options);
|
|
||||||
if (!layer) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
layer.feature = L.GeoJSON.asFeature(geojson);
|
|
||||||
|
|
||||||
layer.defaultOptions = layer.options;
|
|
||||||
this.resetStyle(layer);
|
|
||||||
|
|
||||||
if (options.onEachFeature) {
|
|
||||||
options.onEachFeature(geojson, layer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.addLayer(layer);
|
|
||||||
},
|
|
||||||
|
|
||||||
_pointToLayer: function (pointToLayerFn, geojson, latlng, options) {
|
|
||||||
return pointToLayerFn
|
|
||||||
? pointToLayerFn(geojson, latlng)
|
|
||||||
: new L.Marker(
|
|
||||||
latlng,
|
|
||||||
options && options.markersInheritOptions && options
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
@ -1,807 +0,0 @@
|
|||||||
// Packaging/modules magic dance.
|
|
||||||
(function (factory) {
|
|
||||||
var L;
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD
|
|
||||||
define(['leaflet'], factory);
|
|
||||||
} else if (typeof module !== 'undefined') {
|
|
||||||
// Node/CommonJS
|
|
||||||
L = require('leaflet');
|
|
||||||
module.exports = factory(L);
|
|
||||||
} else {
|
|
||||||
// Browser globals
|
|
||||||
if (typeof window.L === 'undefined')
|
|
||||||
throw 'Leaflet must be loaded first';
|
|
||||||
factory(window.L);
|
|
||||||
}
|
|
||||||
}(function (L) {
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
L.Polyline._flat = L.LineUtil.isFlat || L.Polyline._flat || function (latlngs) {
|
|
||||||
// true if it's a flat array of latlngs; false if nested
|
|
||||||
return !L.Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @fileOverview Leaflet Geometry utilities for distances and linear referencing.
|
|
||||||
* @name L.GeometryUtil
|
|
||||||
*/
|
|
||||||
|
|
||||||
L.GeometryUtil = L.extend(L.GeometryUtil || {}, {
|
|
||||||
|
|
||||||
/**
|
|
||||||
Shortcut function for planar distance between two {L.LatLng} at current zoom.
|
|
||||||
|
|
||||||
@tutorial distance-length
|
|
||||||
|
|
||||||
@param {L.Map} map Leaflet map to be used for this method
|
|
||||||
@param {L.LatLng} latlngA geographical point A
|
|
||||||
@param {L.LatLng} latlngB geographical point B
|
|
||||||
@returns {Number} planar distance
|
|
||||||
*/
|
|
||||||
distance: function (map, latlngA, latlngB) {
|
|
||||||
return map.latLngToLayerPoint(latlngA).distanceTo(map.latLngToLayerPoint(latlngB));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Shortcut function for planar distance between a {L.LatLng} and a segment (A-B).
|
|
||||||
@param {L.Map} map Leaflet map to be used for this method
|
|
||||||
@param {L.LatLng} latlng - The position to search
|
|
||||||
@param {L.LatLng} latlngA geographical point A of the segment
|
|
||||||
@param {L.LatLng} latlngB geographical point B of the segment
|
|
||||||
@returns {Number} planar distance
|
|
||||||
*/
|
|
||||||
distanceSegment: function (map, latlng, latlngA, latlngB) {
|
|
||||||
var p = map.latLngToLayerPoint(latlng),
|
|
||||||
p1 = map.latLngToLayerPoint(latlngA),
|
|
||||||
p2 = map.latLngToLayerPoint(latlngB);
|
|
||||||
return L.LineUtil.pointToSegmentDistance(p, p1, p2);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Shortcut function for converting distance to readable distance.
|
|
||||||
@param {Number} distance distance to be converted
|
|
||||||
@param {String} unit 'metric' or 'imperial'
|
|
||||||
@returns {String} in yard or miles
|
|
||||||
*/
|
|
||||||
readableDistance: function (distance, unit) {
|
|
||||||
var isMetric = (unit !== 'imperial'),
|
|
||||||
distanceStr;
|
|
||||||
if (isMetric) {
|
|
||||||
// show metres when distance is < 1km, then show km
|
|
||||||
if (distance > 1000) {
|
|
||||||
distanceStr = (distance / 1000).toFixed(2) + ' km';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
distanceStr = distance.toFixed(1) + ' m';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
distance *= 1.09361;
|
|
||||||
if (distance > 1760) {
|
|
||||||
distanceStr = (distance / 1760).toFixed(2) + ' miles';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
distanceStr = distance.toFixed(1) + ' yd';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return distanceStr;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns true if the latlng belongs to segment A-B
|
|
||||||
@param {L.LatLng} latlng - The position to search
|
|
||||||
@param {L.LatLng} latlngA geographical point A of the segment
|
|
||||||
@param {L.LatLng} latlngB geographical point B of the segment
|
|
||||||
@param {?Number} [tolerance=0.2] tolerance to accept if latlng belongs really
|
|
||||||
@returns {boolean}
|
|
||||||
*/
|
|
||||||
belongsSegment: function(latlng, latlngA, latlngB, tolerance) {
|
|
||||||
tolerance = tolerance === undefined ? 0.2 : tolerance;
|
|
||||||
var hypotenuse = latlngA.distanceTo(latlngB),
|
|
||||||
delta = latlngA.distanceTo(latlng) + latlng.distanceTo(latlngB) - hypotenuse;
|
|
||||||
return delta/hypotenuse < tolerance;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns total length of line
|
|
||||||
* @tutorial distance-length
|
|
||||||
*
|
|
||||||
* @param {L.Polyline|Array<L.Point>|Array<L.LatLng>} coords Set of coordinates
|
|
||||||
* @returns {Number} Total length (pixels for Point, meters for LatLng)
|
|
||||||
*/
|
|
||||||
length: function (coords) {
|
|
||||||
var accumulated = L.GeometryUtil.accumulatedLengths(coords);
|
|
||||||
return accumulated.length > 0 ? accumulated[accumulated.length-1] : 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of accumulated length along a line.
|
|
||||||
* @param {L.Polyline|Array<L.Point>|Array<L.LatLng>} coords Set of coordinates
|
|
||||||
* @returns {Array<Number>} Array of accumulated lengths (pixels for Point, meters for LatLng)
|
|
||||||
*/
|
|
||||||
accumulatedLengths: function (coords) {
|
|
||||||
if (typeof coords.getLatLngs == 'function') {
|
|
||||||
coords = coords.getLatLngs();
|
|
||||||
}
|
|
||||||
if (coords.length === 0)
|
|
||||||
return [];
|
|
||||||
var total = 0,
|
|
||||||
lengths = [0];
|
|
||||||
for (var i = 0, n = coords.length - 1; i< n; i++) {
|
|
||||||
total += coords[i].distanceTo(coords[i+1]);
|
|
||||||
lengths.push(total);
|
|
||||||
}
|
|
||||||
return lengths;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the closest point of a {L.LatLng} on the segment (A-B)
|
|
||||||
|
|
||||||
@tutorial closest
|
|
||||||
|
|
||||||
@param {L.Map} map Leaflet map to be used for this method
|
|
||||||
@param {L.LatLng} latlng - The position to search
|
|
||||||
@param {L.LatLng} latlngA geographical point A of the segment
|
|
||||||
@param {L.LatLng} latlngB geographical point B of the segment
|
|
||||||
@returns {L.LatLng} Closest geographical point
|
|
||||||
*/
|
|
||||||
closestOnSegment: function (map, latlng, latlngA, latlngB) {
|
|
||||||
var maxzoom = map.getMaxZoom();
|
|
||||||
if (maxzoom === Infinity)
|
|
||||||
maxzoom = map.getZoom();
|
|
||||||
var p = map.project(latlng, maxzoom),
|
|
||||||
p1 = map.project(latlngA, maxzoom),
|
|
||||||
p2 = map.project(latlngB, maxzoom),
|
|
||||||
closest = L.LineUtil.closestPointOnSegment(p, p1, p2);
|
|
||||||
return map.unproject(closest, maxzoom);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the closest point of a {L.LatLng} on a {L.Circle}
|
|
||||||
|
|
||||||
@tutorial closest
|
|
||||||
|
|
||||||
@param {L.LatLng} latlng - The position to search
|
|
||||||
@param {L.Circle} circle - A Circle defined by a center and a radius
|
|
||||||
@returns {L.LatLng} Closest geographical point on the circle circumference
|
|
||||||
*/
|
|
||||||
closestOnCircle: function (circle, latLng) {
|
|
||||||
const center = circle.getLatLng();
|
|
||||||
const circleRadius = circle.getRadius();
|
|
||||||
const radius = typeof circleRadius === 'number' ? circleRadius : circleRadius.radius;
|
|
||||||
const x = latLng.lng;
|
|
||||||
const y = latLng.lat;
|
|
||||||
const cx = center.lng;
|
|
||||||
const cy = center.lat;
|
|
||||||
// dx and dy is the vector from the circle's center to latLng
|
|
||||||
const dx = x - cx;
|
|
||||||
const dy = y - cy;
|
|
||||||
|
|
||||||
// distance between the point and the circle's center
|
|
||||||
const distance = Math.sqrt(dx * dx + dy * dy)
|
|
||||||
|
|
||||||
// Calculate the closest point on the circle by adding the normalized vector to the center
|
|
||||||
const tx = cx + (dx / distance) * radius;
|
|
||||||
const ty = cy + (dy / distance) * radius;
|
|
||||||
|
|
||||||
return new L.LatLng(ty, tx);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the closest latlng on layer.
|
|
||||||
|
|
||||||
Accept nested arrays
|
|
||||||
|
|
||||||
@tutorial closest
|
|
||||||
|
|
||||||
@param {L.Map} map Leaflet map to be used for this method
|
|
||||||
@param {Array<L.LatLng>|Array<Array<L.LatLng>>|L.PolyLine|L.Polygon} layer - Layer that contains the result
|
|
||||||
@param {L.LatLng} latlng - The position to search
|
|
||||||
@param {?boolean} [vertices=false] - Whether to restrict to path vertices.
|
|
||||||
@returns {L.LatLng} Closest geographical point or null if layer param is incorrect
|
|
||||||
*/
|
|
||||||
closest: function (map, layer, latlng, vertices) {
|
|
||||||
|
|
||||||
var latlngs,
|
|
||||||
mindist = Infinity,
|
|
||||||
result = null,
|
|
||||||
i, n, distance, subResult;
|
|
||||||
|
|
||||||
if (layer instanceof Array) {
|
|
||||||
// if layer is Array<Array<T>>
|
|
||||||
if (layer[0] instanceof Array && typeof layer[0][0] !== 'number') {
|
|
||||||
// if we have nested arrays, we calc the closest for each array
|
|
||||||
// recursive
|
|
||||||
for (i = 0; i < layer.length; i++) {
|
|
||||||
subResult = L.GeometryUtil.closest(map, layer[i], latlng, vertices);
|
|
||||||
if (subResult && subResult.distance < mindist) {
|
|
||||||
mindist = subResult.distance;
|
|
||||||
result = subResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} else if (layer[0] instanceof L.LatLng
|
|
||||||
|| typeof layer[0][0] === 'number'
|
|
||||||
|| typeof layer[0].lat === 'number') { // we could have a latlng as [x,y] with x & y numbers or {lat, lng}
|
|
||||||
layer = L.polyline(layer);
|
|
||||||
} else {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we don't have here a Polyline, that means layer is incorrect
|
|
||||||
// see https://github.com/makinacorpus/Leaflet.GeometryUtil/issues/23
|
|
||||||
if (! ( layer instanceof L.Polyline ) )
|
|
||||||
return result;
|
|
||||||
|
|
||||||
// deep copy of latlngs
|
|
||||||
latlngs = JSON.parse(JSON.stringify(layer.getLatLngs().slice(0)));
|
|
||||||
|
|
||||||
// add the last segment for L.Polygon
|
|
||||||
if (layer instanceof L.Polygon) {
|
|
||||||
// add the last segment for each child that is a nested array
|
|
||||||
var addLastSegment = function(latlngs) {
|
|
||||||
if (L.Polyline._flat(latlngs)) {
|
|
||||||
latlngs.push(latlngs[0]);
|
|
||||||
} else {
|
|
||||||
for (var i = 0; i < latlngs.length; i++) {
|
|
||||||
addLastSegment(latlngs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
addLastSegment(latlngs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// we have a multi polygon / multi polyline / polygon with holes
|
|
||||||
// use recursive to explore and return the good result
|
|
||||||
if ( ! L.Polyline._flat(latlngs) ) {
|
|
||||||
for (i = 0; i < latlngs.length; i++) {
|
|
||||||
// if we are at the lower level, and if we have a L.Polygon, we add the last segment
|
|
||||||
subResult = L.GeometryUtil.closest(map, latlngs[i], latlng, vertices);
|
|
||||||
if (subResult.distance < mindist) {
|
|
||||||
mindist = subResult.distance;
|
|
||||||
result = subResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// Lookup vertices
|
|
||||||
if (vertices) {
|
|
||||||
for(i = 0, n = latlngs.length; i < n; i++) {
|
|
||||||
var ll = latlngs[i];
|
|
||||||
distance = L.GeometryUtil.distance(map, latlng, ll);
|
|
||||||
if (distance < mindist) {
|
|
||||||
mindist = distance;
|
|
||||||
result = ll;
|
|
||||||
result.distance = distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep the closest point of all segments
|
|
||||||
for (i = 0, n = latlngs.length; i < n-1; i++) {
|
|
||||||
var latlngA = latlngs[i],
|
|
||||||
latlngB = latlngs[i+1];
|
|
||||||
distance = L.GeometryUtil.distanceSegment(map, latlng, latlngA, latlngB);
|
|
||||||
if (distance <= mindist) {
|
|
||||||
mindist = distance;
|
|
||||||
result = L.GeometryUtil.closestOnSegment(map, latlng, latlngA, latlngB);
|
|
||||||
result.distance = distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the closest layer to latlng among a list of layers.
|
|
||||||
|
|
||||||
@tutorial closest
|
|
||||||
|
|
||||||
@param {L.Map} map Leaflet map to be used for this method
|
|
||||||
@param {Array<L.ILayer>} layers Set of layers
|
|
||||||
@param {L.LatLng} latlng - The position to search
|
|
||||||
@returns {object} ``{layer, latlng, distance}`` or ``null`` if list is empty;
|
|
||||||
*/
|
|
||||||
closestLayer: function (map, layers, latlng) {
|
|
||||||
var mindist = Infinity,
|
|
||||||
result = null,
|
|
||||||
ll = null,
|
|
||||||
distance = Infinity;
|
|
||||||
|
|
||||||
for (var i = 0, n = layers.length; i < n; i++) {
|
|
||||||
var layer = layers[i];
|
|
||||||
if (layer instanceof L.LayerGroup) {
|
|
||||||
// recursive
|
|
||||||
var subResult = L.GeometryUtil.closestLayer(map, layer.getLayers(), latlng);
|
|
||||||
if (subResult.distance < mindist) {
|
|
||||||
mindist = subResult.distance;
|
|
||||||
result = subResult;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (layer instanceof L.Circle){
|
|
||||||
ll = this.closestOnCircle(layer, latlng);
|
|
||||||
distance = L.GeometryUtil.distance(map, latlng, ll);
|
|
||||||
} else
|
|
||||||
// Single dimension, snap on points, else snap on closest
|
|
||||||
if (typeof layer.getLatLng == 'function') {
|
|
||||||
ll = layer.getLatLng();
|
|
||||||
distance = L.GeometryUtil.distance(map, latlng, ll);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ll = L.GeometryUtil.closest(map, layer, latlng);
|
|
||||||
if (ll) distance = ll.distance; // Can return null if layer has no points.
|
|
||||||
}
|
|
||||||
if (distance < mindist) {
|
|
||||||
mindist = distance;
|
|
||||||
result = {layer: layer, latlng: ll, distance: distance};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the n closest layers to latlng among a list of input layers.
|
|
||||||
|
|
||||||
@param {L.Map} map - Leaflet map to be used for this method
|
|
||||||
@param {Array<L.ILayer>} layers - Set of layers
|
|
||||||
@param {L.LatLng} latlng - The position to search
|
|
||||||
@param {?Number} [n=layers.length] - the expected number of output layers.
|
|
||||||
@returns {Array<object>} an array of objects ``{layer, latlng, distance}`` or ``null`` if the input is invalid (empty list or negative n)
|
|
||||||
*/
|
|
||||||
nClosestLayers: function (map, layers, latlng, n) {
|
|
||||||
n = typeof n === 'number' ? n : layers.length;
|
|
||||||
|
|
||||||
if (n < 1 || layers.length < 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var results = [];
|
|
||||||
var distance, ll;
|
|
||||||
|
|
||||||
for (var i = 0, m = layers.length; i < m; i++) {
|
|
||||||
var layer = layers[i];
|
|
||||||
if (layer instanceof L.LayerGroup) {
|
|
||||||
// recursive
|
|
||||||
var subResult = L.GeometryUtil.closestLayer(map, layer.getLayers(), latlng);
|
|
||||||
results.push(subResult);
|
|
||||||
} else {
|
|
||||||
if (layer instanceof L.Circle){
|
|
||||||
ll = this.closestOnCircle(layer, latlng);
|
|
||||||
distance = L.GeometryUtil.distance(map, latlng, ll);
|
|
||||||
} else
|
|
||||||
// Single dimension, snap on points, else snap on closest
|
|
||||||
if (typeof layer.getLatLng == 'function') {
|
|
||||||
ll = layer.getLatLng();
|
|
||||||
distance = L.GeometryUtil.distance(map, latlng, ll);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ll = L.GeometryUtil.closest(map, layer, latlng);
|
|
||||||
if (ll) distance = ll.distance; // Can return null if layer has no points.
|
|
||||||
}
|
|
||||||
results.push({layer: layer, latlng: ll, distance: distance});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results.sort(function(a, b) {
|
|
||||||
return a.distance - b.distance;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (results.length > n) {
|
|
||||||
return results.slice(0, n);
|
|
||||||
} else {
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all layers within a radius of the given position, in an ascending order of distance.
|
|
||||||
@param {L.Map} map Leaflet map to be used for this method
|
|
||||||
@param {Array<ILayer>} layers - A list of layers.
|
|
||||||
@param {L.LatLng} latlng - The position to search
|
|
||||||
@param {?Number} [radius=Infinity] - Search radius in pixels
|
|
||||||
@return {object[]} an array of objects including layer within the radius, closest latlng, and distance
|
|
||||||
*/
|
|
||||||
layersWithin: function(map, layers, latlng, radius) {
|
|
||||||
radius = typeof radius == 'number' ? radius : Infinity;
|
|
||||||
|
|
||||||
var results = [];
|
|
||||||
var ll = null;
|
|
||||||
var distance = 0;
|
|
||||||
|
|
||||||
for (var i = 0, n = layers.length; i < n; i++) {
|
|
||||||
var layer = layers[i];
|
|
||||||
|
|
||||||
if (typeof layer.getLatLng == 'function') {
|
|
||||||
ll = layer.getLatLng();
|
|
||||||
distance = L.GeometryUtil.distance(map, latlng, ll);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ll = L.GeometryUtil.closest(map, layer, latlng);
|
|
||||||
if (ll) distance = ll.distance; // Can return null if layer has no points.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ll && distance < radius) {
|
|
||||||
results.push({layer: layer, latlng: ll, distance: distance});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var sortedResults = results.sort(function(a, b) {
|
|
||||||
return a.distance - b.distance;
|
|
||||||
});
|
|
||||||
|
|
||||||
return sortedResults;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the closest position from specified {LatLng} among specified layers,
|
|
||||||
with a maximum tolerance in pixels, providing snapping behaviour.
|
|
||||||
|
|
||||||
@tutorial closest
|
|
||||||
|
|
||||||
@param {L.Map} map Leaflet map to be used for this method
|
|
||||||
@param {Array<ILayer>} layers - A list of layers to snap on.
|
|
||||||
@param {L.LatLng} latlng - The position to snap
|
|
||||||
@param {?Number} [tolerance=Infinity] - Maximum number of pixels.
|
|
||||||
@param {?boolean} [withVertices=true] - Snap to layers vertices or segment points (not only vertex)
|
|
||||||
@returns {object} with snapped {LatLng} and snapped {Layer} or null if tolerance exceeded.
|
|
||||||
*/
|
|
||||||
closestLayerSnap: function (map, layers, latlng, tolerance, withVertices) {
|
|
||||||
tolerance = typeof tolerance == 'number' ? tolerance : Infinity;
|
|
||||||
withVertices = typeof withVertices == 'boolean' ? withVertices : true;
|
|
||||||
|
|
||||||
var result = L.GeometryUtil.closestLayer(map, layers, latlng);
|
|
||||||
if (!result || result.distance > tolerance)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// If snapped layer is linear, try to snap on vertices (extremities and middle points)
|
|
||||||
if (withVertices && typeof result.layer.getLatLngs == 'function') {
|
|
||||||
var closest = L.GeometryUtil.closest(map, result.layer, result.latlng, true);
|
|
||||||
if (closest.distance < tolerance) {
|
|
||||||
result.latlng = closest;
|
|
||||||
result.distance = L.GeometryUtil.distance(map, closest, latlng);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the Point located on a segment at the specified ratio of the segment length.
|
|
||||||
@param {L.Point} pA coordinates of point A
|
|
||||||
@param {L.Point} pB coordinates of point B
|
|
||||||
@param {Number} the length ratio, expressed as a decimal between 0 and 1, inclusive.
|
|
||||||
@returns {L.Point} the interpolated point.
|
|
||||||
*/
|
|
||||||
interpolateOnPointSegment: function (pA, pB, ratio) {
|
|
||||||
return L.point(
|
|
||||||
(pA.x * (1 - ratio)) + (ratio * pB.x),
|
|
||||||
(pA.y * (1 - ratio)) + (ratio * pB.y)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the coordinate of the point located on a line at the specified ratio of the line length.
|
|
||||||
@param {L.Map} map Leaflet map to be used for this method
|
|
||||||
@param {Array<L.LatLng>|L.PolyLine} latlngs Set of geographical points
|
|
||||||
@param {Number} ratio the length ratio, expressed as a decimal between 0 and 1, inclusive
|
|
||||||
@returns {Object} an object with latLng ({LatLng}) and predecessor ({Number}), the index of the preceding vertex in the Polyline
|
|
||||||
(-1 if the interpolated point is the first vertex)
|
|
||||||
*/
|
|
||||||
interpolateOnLine: function (map, latLngs, ratio) {
|
|
||||||
latLngs = (latLngs instanceof L.Polyline) ? latLngs.getLatLngs() : latLngs;
|
|
||||||
var n = latLngs.length;
|
|
||||||
if (n < 2) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure the ratio is between 0 and 1;
|
|
||||||
ratio = Math.max(Math.min(ratio, 1), 0);
|
|
||||||
|
|
||||||
if (ratio === 0) {
|
|
||||||
return {
|
|
||||||
latLng: latLngs[0] instanceof L.LatLng ? latLngs[0] : L.latLng(latLngs[0]),
|
|
||||||
predecessor: -1
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (ratio == 1) {
|
|
||||||
return {
|
|
||||||
latLng: latLngs[latLngs.length -1] instanceof L.LatLng ? latLngs[latLngs.length -1] : L.latLng(latLngs[latLngs.length -1]),
|
|
||||||
predecessor: latLngs.length - 2
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// project the LatLngs as Points,
|
|
||||||
// and compute total planar length of the line at max precision
|
|
||||||
var maxzoom = map.getMaxZoom();
|
|
||||||
if (maxzoom === Infinity)
|
|
||||||
maxzoom = map.getZoom();
|
|
||||||
var pts = [];
|
|
||||||
var lineLength = 0;
|
|
||||||
for(var i = 0; i < n; i++) {
|
|
||||||
pts[i] = map.project(latLngs[i], maxzoom);
|
|
||||||
if(i > 0)
|
|
||||||
lineLength += pts[i-1].distanceTo(pts[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var ratioDist = lineLength * ratio;
|
|
||||||
|
|
||||||
// follow the line segments [ab], adding lengths,
|
|
||||||
// until we find the segment where the points should lie on
|
|
||||||
var cumulativeDistanceToA = 0, cumulativeDistanceToB = 0;
|
|
||||||
for (var i = 0; cumulativeDistanceToB < ratioDist; i++) {
|
|
||||||
var pointA = pts[i], pointB = pts[i+1];
|
|
||||||
|
|
||||||
cumulativeDistanceToA = cumulativeDistanceToB;
|
|
||||||
cumulativeDistanceToB += pointA.distanceTo(pointB);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pointA == undefined && pointB == undefined) { // Happens when line has no length
|
|
||||||
var pointA = pts[0], pointB = pts[1], i = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute the ratio relative to the segment [ab]
|
|
||||||
var segmentRatio = ((cumulativeDistanceToB - cumulativeDistanceToA) !== 0) ? ((ratioDist - cumulativeDistanceToA) / (cumulativeDistanceToB - cumulativeDistanceToA)) : 0;
|
|
||||||
var interpolatedPoint = L.GeometryUtil.interpolateOnPointSegment(pointA, pointB, segmentRatio);
|
|
||||||
return {
|
|
||||||
latLng: map.unproject(interpolatedPoint, maxzoom),
|
|
||||||
predecessor: i-1
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns a float between 0 and 1 representing the location of the
|
|
||||||
closest point on polyline to the given latlng, as a fraction of total line length.
|
|
||||||
(opposite of L.GeometryUtil.interpolateOnLine())
|
|
||||||
@param {L.Map} map Leaflet map to be used for this method
|
|
||||||
@param {L.PolyLine} polyline Polyline on which the latlng will be search
|
|
||||||
@param {L.LatLng} latlng The position to search
|
|
||||||
@returns {Number} Float between 0 and 1
|
|
||||||
*/
|
|
||||||
locateOnLine: function (map, polyline, latlng) {
|
|
||||||
var latlngs = polyline.getLatLngs();
|
|
||||||
if (latlng.equals(latlngs[0]))
|
|
||||||
return 0.0;
|
|
||||||
if (latlng.equals(latlngs[latlngs.length-1]))
|
|
||||||
return 1.0;
|
|
||||||
|
|
||||||
var point = L.GeometryUtil.closest(map, polyline, latlng, false),
|
|
||||||
lengths = L.GeometryUtil.accumulatedLengths(latlngs),
|
|
||||||
total_length = lengths[lengths.length-1],
|
|
||||||
portion = 0,
|
|
||||||
found = false;
|
|
||||||
for (var i=0, n = latlngs.length-1; i < n; i++) {
|
|
||||||
var l1 = latlngs[i],
|
|
||||||
l2 = latlngs[i+1];
|
|
||||||
portion = lengths[i];
|
|
||||||
if (L.GeometryUtil.belongsSegment(point, l1, l2, 0.001)) {
|
|
||||||
portion += l1.distanceTo(point);
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
throw "Could not interpolate " + latlng.toString() + " within " + polyline.toString();
|
|
||||||
}
|
|
||||||
return portion / total_length;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns a clone with reversed coordinates.
|
|
||||||
@param {L.PolyLine} polyline polyline to reverse
|
|
||||||
@returns {L.PolyLine} polyline reversed
|
|
||||||
*/
|
|
||||||
reverse: function (polyline) {
|
|
||||||
return L.polyline(polyline.getLatLngs().slice(0).reverse());
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns a sub-part of the polyline, from start to end.
|
|
||||||
If start is superior to end, returns extraction from inverted line.
|
|
||||||
@param {L.Map} map Leaflet map to be used for this method
|
|
||||||
@param {L.PolyLine} polyline Polyline on which will be extracted the sub-part
|
|
||||||
@param {Number} start ratio, expressed as a decimal between 0 and 1, inclusive
|
|
||||||
@param {Number} end ratio, expressed as a decimal between 0 and 1, inclusive
|
|
||||||
@returns {Array<L.LatLng>} new polyline
|
|
||||||
*/
|
|
||||||
extract: function (map, polyline, start, end) {
|
|
||||||
if (start > end) {
|
|
||||||
return L.GeometryUtil.extract(map, L.GeometryUtil.reverse(polyline), 1.0-start, 1.0-end);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bound start and end to [0-1]
|
|
||||||
start = Math.max(Math.min(start, 1), 0);
|
|
||||||
end = Math.max(Math.min(end, 1), 0);
|
|
||||||
|
|
||||||
var latlngs = polyline.getLatLngs(),
|
|
||||||
startpoint = L.GeometryUtil.interpolateOnLine(map, polyline, start),
|
|
||||||
endpoint = L.GeometryUtil.interpolateOnLine(map, polyline, end);
|
|
||||||
// Return single point if start == end
|
|
||||||
if (start == end) {
|
|
||||||
var point = L.GeometryUtil.interpolateOnLine(map, polyline, end);
|
|
||||||
return [point.latLng];
|
|
||||||
}
|
|
||||||
// Array.slice() works indexes at 0
|
|
||||||
if (startpoint.predecessor == -1)
|
|
||||||
startpoint.predecessor = 0;
|
|
||||||
if (endpoint.predecessor == -1)
|
|
||||||
endpoint.predecessor = 0;
|
|
||||||
var result = latlngs.slice(startpoint.predecessor+1, endpoint.predecessor+1);
|
|
||||||
result.unshift(startpoint.latLng);
|
|
||||||
result.push(endpoint.latLng);
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns true if first polyline ends where other second starts.
|
|
||||||
@param {L.PolyLine} polyline First polyline
|
|
||||||
@param {L.PolyLine} other Second polyline
|
|
||||||
@returns {bool}
|
|
||||||
*/
|
|
||||||
isBefore: function (polyline, other) {
|
|
||||||
if (!other) return false;
|
|
||||||
var lla = polyline.getLatLngs(),
|
|
||||||
llb = other.getLatLngs();
|
|
||||||
return (lla[lla.length-1]).equals(llb[0]);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns true if first polyline starts where second ends.
|
|
||||||
@param {L.PolyLine} polyline First polyline
|
|
||||||
@param {L.PolyLine} other Second polyline
|
|
||||||
@returns {bool}
|
|
||||||
*/
|
|
||||||
isAfter: function (polyline, other) {
|
|
||||||
if (!other) return false;
|
|
||||||
var lla = polyline.getLatLngs(),
|
|
||||||
llb = other.getLatLngs();
|
|
||||||
return (lla[0]).equals(llb[llb.length-1]);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns true if first polyline starts where second ends or start.
|
|
||||||
@param {L.PolyLine} polyline First polyline
|
|
||||||
@param {L.PolyLine} other Second polyline
|
|
||||||
@returns {bool}
|
|
||||||
*/
|
|
||||||
startsAtExtremity: function (polyline, other) {
|
|
||||||
if (!other) return false;
|
|
||||||
var lla = polyline.getLatLngs(),
|
|
||||||
llb = other.getLatLngs(),
|
|
||||||
start = lla[0];
|
|
||||||
return start.equals(llb[0]) || start.equals(llb[llb.length-1]);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns horizontal angle in degres between two points.
|
|
||||||
@param {L.Point} a Coordinates of point A
|
|
||||||
@param {L.Point} b Coordinates of point B
|
|
||||||
@returns {Number} horizontal angle
|
|
||||||
*/
|
|
||||||
computeAngle: function(a, b) {
|
|
||||||
return (Math.atan2(b.y - a.y, b.x - a.x) * 180 / Math.PI);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns slope (Ax+B) between two points.
|
|
||||||
@param {L.Point} a Coordinates of point A
|
|
||||||
@param {L.Point} b Coordinates of point B
|
|
||||||
@returns {Object} with ``a`` and ``b`` properties.
|
|
||||||
*/
|
|
||||||
computeSlope: function(a, b) {
|
|
||||||
var s = (b.y - a.y) / (b.x - a.x),
|
|
||||||
o = a.y - (s * a.x);
|
|
||||||
return {'a': s, 'b': o};
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns LatLng of rotated point around specified LatLng center.
|
|
||||||
@param {L.LatLng} latlngPoint: point to rotate
|
|
||||||
@param {double} angleDeg: angle to rotate in degrees
|
|
||||||
@param {L.LatLng} latlngCenter: center of rotation
|
|
||||||
@returns {L.LatLng} rotated point
|
|
||||||
*/
|
|
||||||
rotatePoint: function(map, latlngPoint, angleDeg, latlngCenter) {
|
|
||||||
var maxzoom = map.getMaxZoom();
|
|
||||||
if (maxzoom === Infinity)
|
|
||||||
maxzoom = map.getZoom();
|
|
||||||
var angleRad = angleDeg*Math.PI/180,
|
|
||||||
pPoint = map.project(latlngPoint, maxzoom),
|
|
||||||
pCenter = map.project(latlngCenter, maxzoom),
|
|
||||||
x2 = Math.cos(angleRad)*(pPoint.x-pCenter.x) - Math.sin(angleRad)*(pPoint.y-pCenter.y) + pCenter.x,
|
|
||||||
y2 = Math.sin(angleRad)*(pPoint.x-pCenter.x) + Math.cos(angleRad)*(pPoint.y-pCenter.y) + pCenter.y;
|
|
||||||
return map.unproject(new L.Point(x2,y2), maxzoom);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the bearing in degrees clockwise from north (0 degrees)
|
|
||||||
from the first L.LatLng to the second, at the first LatLng
|
|
||||||
@param {L.LatLng} latlng1: origin point of the bearing
|
|
||||||
@param {L.LatLng} latlng2: destination point of the bearing
|
|
||||||
@returns {float} degrees clockwise from north.
|
|
||||||
*/
|
|
||||||
bearing: function(latlng1, latlng2) {
|
|
||||||
var rad = Math.PI / 180,
|
|
||||||
lat1 = latlng1.lat * rad,
|
|
||||||
lat2 = latlng2.lat * rad,
|
|
||||||
lon1 = latlng1.lng * rad,
|
|
||||||
lon2 = latlng2.lng * rad,
|
|
||||||
y = Math.sin(lon2 - lon1) * Math.cos(lat2),
|
|
||||||
x = Math.cos(lat1) * Math.sin(lat2) -
|
|
||||||
Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
|
|
||||||
|
|
||||||
var bearing = ((Math.atan2(y, x) * 180 / Math.PI) + 360) % 360;
|
|
||||||
return bearing >= 180 ? bearing-360 : bearing;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the point that is a distance and heading away from
|
|
||||||
the given origin point.
|
|
||||||
@param {L.LatLng} latlng: origin point
|
|
||||||
@param {float} heading: heading in degrees, clockwise from 0 degrees north.
|
|
||||||
@param {float} distance: distance in meters
|
|
||||||
@returns {L.latLng} the destination point.
|
|
||||||
Many thanks to Chris Veness at http://www.movable-type.co.uk/scripts/latlong.html
|
|
||||||
for a great reference and examples.
|
|
||||||
*/
|
|
||||||
destination: function(latlng, heading, distance) {
|
|
||||||
heading = (heading + 360) % 360;
|
|
||||||
var rad = Math.PI / 180,
|
|
||||||
radInv = 180 / Math.PI,
|
|
||||||
R = L.CRS.Earth.R, // approximation of Earth's radius
|
|
||||||
lon1 = latlng.lng * rad,
|
|
||||||
lat1 = latlng.lat * rad,
|
|
||||||
rheading = heading * rad,
|
|
||||||
sinLat1 = Math.sin(lat1),
|
|
||||||
cosLat1 = Math.cos(lat1),
|
|
||||||
cosDistR = Math.cos(distance / R),
|
|
||||||
sinDistR = Math.sin(distance / R),
|
|
||||||
lat2 = Math.asin(sinLat1 * cosDistR + cosLat1 *
|
|
||||||
sinDistR * Math.cos(rheading)),
|
|
||||||
lon2 = lon1 + Math.atan2(Math.sin(rheading) * sinDistR *
|
|
||||||
cosLat1, cosDistR - sinLat1 * Math.sin(lat2));
|
|
||||||
lon2 = lon2 * radInv;
|
|
||||||
lon2 = lon2 > 180 ? lon2 - 360 : lon2 < -180 ? lon2 + 360 : lon2;
|
|
||||||
return L.latLng([lat2 * radInv, lon2]);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the the angle of the given segment and the Equator in degrees,
|
|
||||||
clockwise from 0 degrees north.
|
|
||||||
@param {L.Map} map: Leaflet map to be used for this method
|
|
||||||
@param {L.LatLng} latlngA: geographical point A of the segment
|
|
||||||
@param {L.LatLng} latlngB: geographical point B of the segment
|
|
||||||
@returns {Float} the angle in degrees.
|
|
||||||
*/
|
|
||||||
angle: function(map, latlngA, latlngB) {
|
|
||||||
var pointA = map.latLngToContainerPoint(latlngA),
|
|
||||||
pointB = map.latLngToContainerPoint(latlngB),
|
|
||||||
angleDeg = Math.atan2(pointB.y - pointA.y, pointB.x - pointA.x) * 180 / Math.PI + 90;
|
|
||||||
angleDeg += angleDeg < 0 ? 360 : 0;
|
|
||||||
return angleDeg;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns a point snaps on the segment and heading away from the given origin point a distance.
|
|
||||||
@param {L.Map} map: Leaflet map to be used for this method
|
|
||||||
@param {L.LatLng} latlngA: geographical point A of the segment
|
|
||||||
@param {L.LatLng} latlngB: geographical point B of the segment
|
|
||||||
@param {float} distance: distance in meters
|
|
||||||
@returns {L.latLng} the destination point.
|
|
||||||
*/
|
|
||||||
destinationOnSegment: function(map, latlngA, latlngB, distance) {
|
|
||||||
var angleDeg = L.GeometryUtil.angle(map, latlngA, latlngB),
|
|
||||||
latlng = L.GeometryUtil.destination(latlngA, angleDeg, distance);
|
|
||||||
return L.GeometryUtil.closestOnSegment(map, latlng, latlngA, latlngB);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return L.GeometryUtil;
|
|
||||||
|
|
||||||
}));
|
|
@ -1,13 +0,0 @@
|
|||||||
.leaflet-control-layers-group-name {
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: .2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-control-layers-group {
|
|
||||||
margin-bottom: .5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-control-layers-scrollbar {
|
|
||||||
overflow-y: scroll;
|
|
||||||
padding-right: 10px;
|
|
||||||
}
|
|
@ -1,374 +0,0 @@
|
|||||||
/* global L */
|
|
||||||
|
|
||||||
// A layer control which provides for layer groupings.
|
|
||||||
// Author: Ishmael Smyrnow
|
|
||||||
L.Control.GroupedLayers = L.Control.extend({
|
|
||||||
|
|
||||||
options: {
|
|
||||||
collapsed: true,
|
|
||||||
position: 'topright',
|
|
||||||
autoZIndex: true,
|
|
||||||
exclusiveGroups: [],
|
|
||||||
groupCheckboxes: false
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function (baseLayers, groupedOverlays, options) {
|
|
||||||
var i, j;
|
|
||||||
L.Util.setOptions(this, options);
|
|
||||||
|
|
||||||
this._layers = [];
|
|
||||||
this._lastZIndex = 0;
|
|
||||||
this._handlingClick = false;
|
|
||||||
this._groupList = [];
|
|
||||||
this._domGroups = [];
|
|
||||||
|
|
||||||
for (i in baseLayers) {
|
|
||||||
this._addLayer(baseLayers[i], i);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i in groupedOverlays) {
|
|
||||||
for (j in groupedOverlays[i]) {
|
|
||||||
this._addLayer(groupedOverlays[i][j], j, i, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onAdd: function (map) {
|
|
||||||
this._initLayout();
|
|
||||||
this._update();
|
|
||||||
|
|
||||||
map
|
|
||||||
.on('layeradd', this._onLayerChange, this)
|
|
||||||
.on('layerremove', this._onLayerChange, this);
|
|
||||||
|
|
||||||
return this._container;
|
|
||||||
},
|
|
||||||
|
|
||||||
onRemove: function (map) {
|
|
||||||
map
|
|
||||||
.off('layeradd', this._onLayerChange, this)
|
|
||||||
.off('layerremove', this._onLayerChange, this);
|
|
||||||
},
|
|
||||||
|
|
||||||
addBaseLayer: function (layer, name) {
|
|
||||||
this._addLayer(layer, name);
|
|
||||||
this._update();
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
addOverlay: function (layer, name, group) {
|
|
||||||
this._addLayer(layer, name, group, true);
|
|
||||||
this._update();
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
removeLayer: function (layer) {
|
|
||||||
var id = L.Util.stamp(layer);
|
|
||||||
var _layer = this._getLayer(id);
|
|
||||||
if (_layer) {
|
|
||||||
delete this._layers[this._layers.indexOf(_layer)];
|
|
||||||
}
|
|
||||||
this._update();
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
_getLayer: function (id) {
|
|
||||||
for (var i = 0; i < this._layers.length; i++) {
|
|
||||||
if (this._layers[i] && L.stamp(this._layers[i].layer) === id) {
|
|
||||||
return this._layers[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_initLayout: function () {
|
|
||||||
var className = 'leaflet-control-layers',
|
|
||||||
container = this._container = L.DomUtil.create('div', className);
|
|
||||||
|
|
||||||
// Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released
|
|
||||||
container.setAttribute('aria-haspopup', true);
|
|
||||||
|
|
||||||
if (L.Browser.touch) {
|
|
||||||
L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
|
|
||||||
} else {
|
|
||||||
L.DomEvent.disableClickPropagation(container);
|
|
||||||
L.DomEvent.on(container, 'wheel', L.DomEvent.stopPropagation);
|
|
||||||
}
|
|
||||||
|
|
||||||
var form = this._form = L.DomUtil.create('form', className + '-list');
|
|
||||||
|
|
||||||
if (this.options.collapsed) {
|
|
||||||
if (!L.Browser.android) {
|
|
||||||
L.DomEvent
|
|
||||||
.on(container, 'mouseover', this._expand, this)
|
|
||||||
.on(container, 'mouseout', this._collapse, this);
|
|
||||||
}
|
|
||||||
var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);
|
|
||||||
link.href = '#';
|
|
||||||
link.title = 'Layers';
|
|
||||||
|
|
||||||
if (L.Browser.touch) {
|
|
||||||
L.DomEvent
|
|
||||||
.on(link, 'click', L.DomEvent.stop)
|
|
||||||
.on(link, 'click', this._expand, this);
|
|
||||||
} else {
|
|
||||||
L.DomEvent.on(link, 'focus', this._expand, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._map.on('click', this._collapse, this);
|
|
||||||
// TODO keyboard accessibility
|
|
||||||
} else {
|
|
||||||
this._expand();
|
|
||||||
}
|
|
||||||
|
|
||||||
this._baseLayersList = L.DomUtil.create('div', className + '-base', form);
|
|
||||||
this._separator = L.DomUtil.create('div', className + '-separator', form);
|
|
||||||
this._overlaysList = L.DomUtil.create('div', className + '-overlays', form);
|
|
||||||
|
|
||||||
container.appendChild(form);
|
|
||||||
},
|
|
||||||
|
|
||||||
_addLayer: function (layer, name, group, overlay) {
|
|
||||||
var id = L.Util.stamp(layer);
|
|
||||||
|
|
||||||
var _layer = {
|
|
||||||
layer: layer,
|
|
||||||
name: name,
|
|
||||||
overlay: overlay
|
|
||||||
};
|
|
||||||
this._layers.push(_layer);
|
|
||||||
|
|
||||||
group = group || '';
|
|
||||||
var groupId = this._indexOf(this._groupList, group);
|
|
||||||
|
|
||||||
if (groupId === -1) {
|
|
||||||
groupId = this._groupList.push(group) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var exclusive = (this._indexOf(this.options.exclusiveGroups, group) !== -1);
|
|
||||||
|
|
||||||
_layer.group = {
|
|
||||||
name: group,
|
|
||||||
id: groupId,
|
|
||||||
exclusive: exclusive
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.options.autoZIndex && layer.setZIndex) {
|
|
||||||
this._lastZIndex++;
|
|
||||||
layer.setZIndex(this._lastZIndex);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_update: function () {
|
|
||||||
if (!this._container) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._baseLayersList.innerHTML = '';
|
|
||||||
this._overlaysList.innerHTML = '';
|
|
||||||
this._domGroups.length = 0;
|
|
||||||
|
|
||||||
var baseLayersPresent = false,
|
|
||||||
overlaysPresent = false,
|
|
||||||
i, obj;
|
|
||||||
|
|
||||||
for (var i = 0; i < this._layers.length; i++) {
|
|
||||||
obj = this._layers[i];
|
|
||||||
this._addItem(obj);
|
|
||||||
overlaysPresent = overlaysPresent || obj.overlay;
|
|
||||||
baseLayersPresent = baseLayersPresent || !obj.overlay;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
|
|
||||||
},
|
|
||||||
|
|
||||||
_onLayerChange: function (e) {
|
|
||||||
var obj = this._getLayer(L.Util.stamp(e.layer)),
|
|
||||||
type;
|
|
||||||
|
|
||||||
if (!obj) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._handlingClick) {
|
|
||||||
this._update();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj.overlay) {
|
|
||||||
type = e.type === 'layeradd' ? 'overlayadd' : 'overlayremove';
|
|
||||||
} else {
|
|
||||||
type = e.type === 'layeradd' ? 'baselayerchange' : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type) {
|
|
||||||
this._map.fire(type, obj);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
|
|
||||||
_createRadioElement: function (name, checked) {
|
|
||||||
var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' + name + '"';
|
|
||||||
if (checked) {
|
|
||||||
radioHtml += ' checked="checked"';
|
|
||||||
}
|
|
||||||
radioHtml += '/>';
|
|
||||||
|
|
||||||
var radioFragment = document.createElement('div');
|
|
||||||
radioFragment.innerHTML = radioHtml;
|
|
||||||
|
|
||||||
return radioFragment.firstChild;
|
|
||||||
},
|
|
||||||
|
|
||||||
_addItem: function (obj) {
|
|
||||||
var label = document.createElement('label'),
|
|
||||||
input,
|
|
||||||
checked = this._map.hasLayer(obj.layer),
|
|
||||||
container,
|
|
||||||
groupRadioName;
|
|
||||||
|
|
||||||
if (obj.overlay) {
|
|
||||||
if (obj.group.exclusive) {
|
|
||||||
groupRadioName = 'leaflet-exclusive-group-layer-' + obj.group.id;
|
|
||||||
input = this._createRadioElement(groupRadioName, checked);
|
|
||||||
} else {
|
|
||||||
input = document.createElement('input');
|
|
||||||
input.type = 'checkbox';
|
|
||||||
input.className = 'leaflet-control-layers-selector';
|
|
||||||
input.defaultChecked = checked;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
input = this._createRadioElement('leaflet-base-layers', checked);
|
|
||||||
}
|
|
||||||
|
|
||||||
input.layerId = L.Util.stamp(obj.layer);
|
|
||||||
input.groupID = obj.group.id;
|
|
||||||
L.DomEvent.on(input, 'click', this._onInputClick, this);
|
|
||||||
|
|
||||||
var name = document.createElement('span');
|
|
||||||
name.innerHTML = ' ' + obj.name;
|
|
||||||
|
|
||||||
label.appendChild(input);
|
|
||||||
label.appendChild(name);
|
|
||||||
|
|
||||||
if (obj.overlay) {
|
|
||||||
container = this._overlaysList;
|
|
||||||
|
|
||||||
var groupContainer = this._domGroups[obj.group.id];
|
|
||||||
|
|
||||||
// Create the group container if it doesn't exist
|
|
||||||
if (!groupContainer) {
|
|
||||||
groupContainer = document.createElement('div');
|
|
||||||
groupContainer.className = 'leaflet-control-layers-group';
|
|
||||||
groupContainer.id = 'leaflet-control-layers-group-' + obj.group.id;
|
|
||||||
|
|
||||||
var groupLabel = document.createElement('label');
|
|
||||||
groupLabel.className = 'leaflet-control-layers-group-label';
|
|
||||||
|
|
||||||
if (obj.group.name !== '' && !obj.group.exclusive) {
|
|
||||||
// ------ add a group checkbox with an _onInputClickGroup function
|
|
||||||
if (this.options.groupCheckboxes) {
|
|
||||||
var groupInput = document.createElement('input');
|
|
||||||
groupInput.type = 'checkbox';
|
|
||||||
groupInput.className = 'leaflet-control-layers-group-selector';
|
|
||||||
groupInput.groupID = obj.group.id;
|
|
||||||
groupInput.legend = this;
|
|
||||||
L.DomEvent.on(groupInput, 'click', this._onGroupInputClick, groupInput);
|
|
||||||
groupLabel.appendChild(groupInput);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var groupName = document.createElement('span');
|
|
||||||
groupName.className = 'leaflet-control-layers-group-name';
|
|
||||||
groupName.innerHTML = obj.group.name;
|
|
||||||
groupLabel.appendChild(groupName);
|
|
||||||
|
|
||||||
groupContainer.appendChild(groupLabel);
|
|
||||||
container.appendChild(groupContainer);
|
|
||||||
|
|
||||||
this._domGroups[obj.group.id] = groupContainer;
|
|
||||||
}
|
|
||||||
|
|
||||||
container = groupContainer;
|
|
||||||
} else {
|
|
||||||
container = this._baseLayersList;
|
|
||||||
}
|
|
||||||
|
|
||||||
container.appendChild(label);
|
|
||||||
|
|
||||||
return label;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onGroupInputClick: function () {
|
|
||||||
var i, input, obj;
|
|
||||||
|
|
||||||
var this_legend = this.legend;
|
|
||||||
this_legend._handlingClick = true;
|
|
||||||
|
|
||||||
var inputs = this_legend._form.getElementsByTagName('input');
|
|
||||||
var inputsLen = inputs.length;
|
|
||||||
|
|
||||||
for (i = 0; i < inputsLen; i++) {
|
|
||||||
input = inputs[i];
|
|
||||||
if (input.groupID === this.groupID && input.className === 'leaflet-control-layers-selector') {
|
|
||||||
input.checked = this.checked;
|
|
||||||
obj = this_legend._getLayer(input.layerId);
|
|
||||||
if (input.checked && !this_legend._map.hasLayer(obj.layer)) {
|
|
||||||
this_legend._map.addLayer(obj.layer);
|
|
||||||
} else if (!input.checked && this_legend._map.hasLayer(obj.layer)) {
|
|
||||||
this_legend._map.removeLayer(obj.layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this_legend._handlingClick = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onInputClick: function () {
|
|
||||||
var i, input, obj,
|
|
||||||
inputs = this._form.getElementsByTagName('input'),
|
|
||||||
inputsLen = inputs.length;
|
|
||||||
|
|
||||||
this._handlingClick = true;
|
|
||||||
|
|
||||||
for (i = 0; i < inputsLen; i++) {
|
|
||||||
input = inputs[i];
|
|
||||||
if (input.className === 'leaflet-control-layers-selector') {
|
|
||||||
obj = this._getLayer(input.layerId);
|
|
||||||
|
|
||||||
if (input.checked && !this._map.hasLayer(obj.layer)) {
|
|
||||||
this._map.addLayer(obj.layer);
|
|
||||||
} else if (!input.checked && this._map.hasLayer(obj.layer)) {
|
|
||||||
this._map.removeLayer(obj.layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this._handlingClick = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
_expand: function () {
|
|
||||||
L.DomUtil.addClass(this._container, 'leaflet-control-layers-expanded');
|
|
||||||
// permits to have a scrollbar if overlays heighter than the map.
|
|
||||||
var acceptableHeight = this._map._size.y - (this._container.offsetTop * 4);
|
|
||||||
if (acceptableHeight < this._form.clientHeight) {
|
|
||||||
L.DomUtil.addClass(this._form, 'leaflet-control-layers-scrollbar');
|
|
||||||
this._form.style.height = acceptableHeight + 'px';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_collapse: function () {
|
|
||||||
this._container.className = this._container.className.replace(' leaflet-control-layers-expanded', '');
|
|
||||||
},
|
|
||||||
|
|
||||||
_indexOf: function (arr, obj) {
|
|
||||||
for (var i = 0, j = arr.length; i < j; i++) {
|
|
||||||
if (arr[i] === obj) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
L.control.groupedLayers = function (baseLayers, groupedOverlays, options) {
|
|
||||||
return new L.Control.GroupedLayers(baseLayers, groupedOverlays, options);
|
|
||||||
};
|
|
@ -1,60 +0,0 @@
|
|||||||
.marker-cluster-small {
|
|
||||||
background-color: rgba(181, 226, 140, 0.6);
|
|
||||||
}
|
|
||||||
.marker-cluster-small div {
|
|
||||||
background-color: rgba(110, 204, 57, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.marker-cluster-medium {
|
|
||||||
background-color: rgba(241, 211, 87, 0.6);
|
|
||||||
}
|
|
||||||
.marker-cluster-medium div {
|
|
||||||
background-color: rgba(240, 194, 12, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.marker-cluster-large {
|
|
||||||
background-color: rgba(253, 156, 115, 0.6);
|
|
||||||
}
|
|
||||||
.marker-cluster-large div {
|
|
||||||
background-color: rgba(241, 128, 23, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* IE 6-8 fallback colors */
|
|
||||||
.leaflet-oldie .marker-cluster-small {
|
|
||||||
background-color: rgb(181, 226, 140);
|
|
||||||
}
|
|
||||||
.leaflet-oldie .marker-cluster-small div {
|
|
||||||
background-color: rgb(110, 204, 57);
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-oldie .marker-cluster-medium {
|
|
||||||
background-color: rgb(241, 211, 87);
|
|
||||||
}
|
|
||||||
.leaflet-oldie .marker-cluster-medium div {
|
|
||||||
background-color: rgb(240, 194, 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaflet-oldie .marker-cluster-large {
|
|
||||||
background-color: rgb(253, 156, 115);
|
|
||||||
}
|
|
||||||
.leaflet-oldie .marker-cluster-large div {
|
|
||||||
background-color: rgb(241, 128, 23);
|
|
||||||
}
|
|
||||||
|
|
||||||
.marker-cluster {
|
|
||||||
background-clip: padding-box;
|
|
||||||
border-radius: 20px;
|
|
||||||
}
|
|
||||||
.marker-cluster div {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-top: 5px;
|
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 15px;
|
|
||||||
font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
|
|
||||||
}
|
|
||||||
.marker-cluster span {
|
|
||||||
line-height: 30px;
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user