Fix European trip return heuristic for weekend location tracking
Adjust European short trip heuristic from >3 days to >1 day to correctly detect when user has returned home from European trips. This fixes the April 29-30, 2023 case where the location incorrectly showed "Sankt Georg, Hamburg" instead of "Bristol" when the user was free (no events scheduled) after the foss-north trip ended on April 27. The previous logic required more than 3 days to pass before assuming return home from European countries, but for short European trips by rail/ferry, users typically return within 1-2 days. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
663dc479c2
commit
ea4980a5d7
6407 changed files with 1072847 additions and 18 deletions
4085
static/bootstrap5/css/bootstrap-grid.css
vendored
Normal file
4085
static/bootstrap5/css/bootstrap-grid.css
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
static/bootstrap5/css/bootstrap-grid.css.map
Normal file
1
static/bootstrap5/css/bootstrap-grid.css.map
Normal file
File diff suppressed because one or more lines are too long
6
static/bootstrap5/css/bootstrap-grid.min.css
vendored
Normal file
6
static/bootstrap5/css/bootstrap-grid.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/bootstrap5/css/bootstrap-grid.min.css.map
Normal file
1
static/bootstrap5/css/bootstrap-grid.min.css.map
Normal file
File diff suppressed because one or more lines are too long
4084
static/bootstrap5/css/bootstrap-grid.rtl.css
vendored
Normal file
4084
static/bootstrap5/css/bootstrap-grid.rtl.css
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
static/bootstrap5/css/bootstrap-grid.rtl.css.map
Normal file
1
static/bootstrap5/css/bootstrap-grid.rtl.css.map
Normal file
File diff suppressed because one or more lines are too long
6
static/bootstrap5/css/bootstrap-grid.rtl.min.css
vendored
Normal file
6
static/bootstrap5/css/bootstrap-grid.rtl.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/bootstrap5/css/bootstrap-grid.rtl.min.css.map
Normal file
1
static/bootstrap5/css/bootstrap-grid.rtl.min.css.map
Normal file
File diff suppressed because one or more lines are too long
597
static/bootstrap5/css/bootstrap-reboot.css
vendored
Normal file
597
static/bootstrap5/css/bootstrap-reboot.css
vendored
Normal file
|
|
@ -0,0 +1,597 @@
|
|||
/*!
|
||||
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2024 The Bootstrap Authors
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root,
|
||||
[data-bs-theme=light] {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-black: #000;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-primary-text-emphasis: #052c65;
|
||||
--bs-secondary-text-emphasis: #2b2f32;
|
||||
--bs-success-text-emphasis: #0a3622;
|
||||
--bs-info-text-emphasis: #055160;
|
||||
--bs-warning-text-emphasis: #664d03;
|
||||
--bs-danger-text-emphasis: #58151c;
|
||||
--bs-light-text-emphasis: #495057;
|
||||
--bs-dark-text-emphasis: #495057;
|
||||
--bs-primary-bg-subtle: #cfe2ff;
|
||||
--bs-secondary-bg-subtle: #e2e3e5;
|
||||
--bs-success-bg-subtle: #d1e7dd;
|
||||
--bs-info-bg-subtle: #cff4fc;
|
||||
--bs-warning-bg-subtle: #fff3cd;
|
||||
--bs-danger-bg-subtle: #f8d7da;
|
||||
--bs-light-bg-subtle: #fcfcfd;
|
||||
--bs-dark-bg-subtle: #ced4da;
|
||||
--bs-primary-border-subtle: #9ec5fe;
|
||||
--bs-secondary-border-subtle: #c4c8cb;
|
||||
--bs-success-border-subtle: #a3cfbb;
|
||||
--bs-info-border-subtle: #9eeaf9;
|
||||
--bs-warning-border-subtle: #ffe69c;
|
||||
--bs-danger-border-subtle: #f1aeb5;
|
||||
--bs-light-border-subtle: #e9ecef;
|
||||
--bs-dark-border-subtle: #adb5bd;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg: #fff;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-emphasis-color: #000;
|
||||
--bs-emphasis-color-rgb: 0, 0, 0;
|
||||
--bs-secondary-color: rgba(33, 37, 41, 0.75);
|
||||
--bs-secondary-color-rgb: 33, 37, 41;
|
||||
--bs-secondary-bg: #e9ecef;
|
||||
--bs-secondary-bg-rgb: 233, 236, 239;
|
||||
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
|
||||
--bs-tertiary-color-rgb: 33, 37, 41;
|
||||
--bs-tertiary-bg: #f8f9fa;
|
||||
--bs-tertiary-bg-rgb: 248, 249, 250;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #0d6efd;
|
||||
--bs-link-color-rgb: 13, 110, 253;
|
||||
--bs-link-decoration: underline;
|
||||
--bs-link-hover-color: #0a58ca;
|
||||
--bs-link-hover-color-rgb: 10, 88, 202;
|
||||
--bs-code-color: #d63384;
|
||||
--bs-highlight-color: #212529;
|
||||
--bs-highlight-bg: #fff3cd;
|
||||
--bs-border-width: 1px;
|
||||
--bs-border-style: solid;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
|
||||
--bs-border-radius: 0.375rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
--bs-border-radius-lg: 0.5rem;
|
||||
--bs-border-radius-xl: 1rem;
|
||||
--bs-border-radius-xxl: 2rem;
|
||||
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
|
||||
--bs-border-radius-pill: 50rem;
|
||||
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
|
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
--bs-focus-ring-width: 0.25rem;
|
||||
--bs-focus-ring-opacity: 0.25;
|
||||
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
|
||||
--bs-form-valid-color: #198754;
|
||||
--bs-form-valid-border-color: #198754;
|
||||
--bs-form-invalid-color: #dc3545;
|
||||
--bs-form-invalid-border-color: #dc3545;
|
||||
}
|
||||
|
||||
[data-bs-theme=dark] {
|
||||
color-scheme: dark;
|
||||
--bs-body-color: #dee2e6;
|
||||
--bs-body-color-rgb: 222, 226, 230;
|
||||
--bs-body-bg: #212529;
|
||||
--bs-body-bg-rgb: 33, 37, 41;
|
||||
--bs-emphasis-color: #fff;
|
||||
--bs-emphasis-color-rgb: 255, 255, 255;
|
||||
--bs-secondary-color: rgba(222, 226, 230, 0.75);
|
||||
--bs-secondary-color-rgb: 222, 226, 230;
|
||||
--bs-secondary-bg: #343a40;
|
||||
--bs-secondary-bg-rgb: 52, 58, 64;
|
||||
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
|
||||
--bs-tertiary-color-rgb: 222, 226, 230;
|
||||
--bs-tertiary-bg: #2b3035;
|
||||
--bs-tertiary-bg-rgb: 43, 48, 53;
|
||||
--bs-primary-text-emphasis: #6ea8fe;
|
||||
--bs-secondary-text-emphasis: #a7acb1;
|
||||
--bs-success-text-emphasis: #75b798;
|
||||
--bs-info-text-emphasis: #6edff6;
|
||||
--bs-warning-text-emphasis: #ffda6a;
|
||||
--bs-danger-text-emphasis: #ea868f;
|
||||
--bs-light-text-emphasis: #f8f9fa;
|
||||
--bs-dark-text-emphasis: #dee2e6;
|
||||
--bs-primary-bg-subtle: #031633;
|
||||
--bs-secondary-bg-subtle: #161719;
|
||||
--bs-success-bg-subtle: #051b11;
|
||||
--bs-info-bg-subtle: #032830;
|
||||
--bs-warning-bg-subtle: #332701;
|
||||
--bs-danger-bg-subtle: #2c0b0e;
|
||||
--bs-light-bg-subtle: #343a40;
|
||||
--bs-dark-bg-subtle: #1a1d20;
|
||||
--bs-primary-border-subtle: #084298;
|
||||
--bs-secondary-border-subtle: #41464b;
|
||||
--bs-success-border-subtle: #0f5132;
|
||||
--bs-info-border-subtle: #087990;
|
||||
--bs-warning-border-subtle: #997404;
|
||||
--bs-danger-border-subtle: #842029;
|
||||
--bs-light-border-subtle: #495057;
|
||||
--bs-dark-border-subtle: #343a40;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #6ea8fe;
|
||||
--bs-link-hover-color: #8bb9fe;
|
||||
--bs-link-color-rgb: 110, 168, 254;
|
||||
--bs-link-hover-color-rgb: 139, 185, 254;
|
||||
--bs-code-color: #e685b5;
|
||||
--bs-highlight-color: #dee2e6;
|
||||
--bs-highlight-bg: #664d03;
|
||||
--bs-border-color: #495057;
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
|
||||
--bs-form-valid-color: #75b798;
|
||||
--bs-form-valid-border-color: #75b798;
|
||||
--bs-form-invalid-color: #ea868f;
|
||||
--bs-form-invalid-border-color: #ea868f;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
border-top: var(--bs-border-width) solid;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: var(--bs-heading-color);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.1875em;
|
||||
color: var(--bs-highlight-color);
|
||||
background-color: var(--bs-highlight-bg);
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-code-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.1875rem 0.375rem;
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-body-bg);
|
||||
background-color: var(--bs-body-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: var(--bs-secondary-color);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: left;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
/* rtl:raw:
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
*/
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
||||
1
static/bootstrap5/css/bootstrap-reboot.css.map
Normal file
1
static/bootstrap5/css/bootstrap-reboot.css.map
Normal file
File diff suppressed because one or more lines are too long
6
static/bootstrap5/css/bootstrap-reboot.min.css
vendored
Normal file
6
static/bootstrap5/css/bootstrap-reboot.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/bootstrap5/css/bootstrap-reboot.min.css.map
Normal file
1
static/bootstrap5/css/bootstrap-reboot.min.css.map
Normal file
File diff suppressed because one or more lines are too long
594
static/bootstrap5/css/bootstrap-reboot.rtl.css
vendored
Normal file
594
static/bootstrap5/css/bootstrap-reboot.rtl.css
vendored
Normal file
|
|
@ -0,0 +1,594 @@
|
|||
/*!
|
||||
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2024 The Bootstrap Authors
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
:root,
|
||||
[data-bs-theme=light] {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-black: #000;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-primary-text-emphasis: #052c65;
|
||||
--bs-secondary-text-emphasis: #2b2f32;
|
||||
--bs-success-text-emphasis: #0a3622;
|
||||
--bs-info-text-emphasis: #055160;
|
||||
--bs-warning-text-emphasis: #664d03;
|
||||
--bs-danger-text-emphasis: #58151c;
|
||||
--bs-light-text-emphasis: #495057;
|
||||
--bs-dark-text-emphasis: #495057;
|
||||
--bs-primary-bg-subtle: #cfe2ff;
|
||||
--bs-secondary-bg-subtle: #e2e3e5;
|
||||
--bs-success-bg-subtle: #d1e7dd;
|
||||
--bs-info-bg-subtle: #cff4fc;
|
||||
--bs-warning-bg-subtle: #fff3cd;
|
||||
--bs-danger-bg-subtle: #f8d7da;
|
||||
--bs-light-bg-subtle: #fcfcfd;
|
||||
--bs-dark-bg-subtle: #ced4da;
|
||||
--bs-primary-border-subtle: #9ec5fe;
|
||||
--bs-secondary-border-subtle: #c4c8cb;
|
||||
--bs-success-border-subtle: #a3cfbb;
|
||||
--bs-info-border-subtle: #9eeaf9;
|
||||
--bs-warning-border-subtle: #ffe69c;
|
||||
--bs-danger-border-subtle: #f1aeb5;
|
||||
--bs-light-border-subtle: #e9ecef;
|
||||
--bs-dark-border-subtle: #adb5bd;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg: #fff;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-emphasis-color: #000;
|
||||
--bs-emphasis-color-rgb: 0, 0, 0;
|
||||
--bs-secondary-color: rgba(33, 37, 41, 0.75);
|
||||
--bs-secondary-color-rgb: 33, 37, 41;
|
||||
--bs-secondary-bg: #e9ecef;
|
||||
--bs-secondary-bg-rgb: 233, 236, 239;
|
||||
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
|
||||
--bs-tertiary-color-rgb: 33, 37, 41;
|
||||
--bs-tertiary-bg: #f8f9fa;
|
||||
--bs-tertiary-bg-rgb: 248, 249, 250;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #0d6efd;
|
||||
--bs-link-color-rgb: 13, 110, 253;
|
||||
--bs-link-decoration: underline;
|
||||
--bs-link-hover-color: #0a58ca;
|
||||
--bs-link-hover-color-rgb: 10, 88, 202;
|
||||
--bs-code-color: #d63384;
|
||||
--bs-highlight-color: #212529;
|
||||
--bs-highlight-bg: #fff3cd;
|
||||
--bs-border-width: 1px;
|
||||
--bs-border-style: solid;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
|
||||
--bs-border-radius: 0.375rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
--bs-border-radius-lg: 0.5rem;
|
||||
--bs-border-radius-xl: 1rem;
|
||||
--bs-border-radius-xxl: 2rem;
|
||||
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
|
||||
--bs-border-radius-pill: 50rem;
|
||||
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
||||
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
|
||||
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
--bs-focus-ring-width: 0.25rem;
|
||||
--bs-focus-ring-opacity: 0.25;
|
||||
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
|
||||
--bs-form-valid-color: #198754;
|
||||
--bs-form-valid-border-color: #198754;
|
||||
--bs-form-invalid-color: #dc3545;
|
||||
--bs-form-invalid-border-color: #dc3545;
|
||||
}
|
||||
|
||||
[data-bs-theme=dark] {
|
||||
color-scheme: dark;
|
||||
--bs-body-color: #dee2e6;
|
||||
--bs-body-color-rgb: 222, 226, 230;
|
||||
--bs-body-bg: #212529;
|
||||
--bs-body-bg-rgb: 33, 37, 41;
|
||||
--bs-emphasis-color: #fff;
|
||||
--bs-emphasis-color-rgb: 255, 255, 255;
|
||||
--bs-secondary-color: rgba(222, 226, 230, 0.75);
|
||||
--bs-secondary-color-rgb: 222, 226, 230;
|
||||
--bs-secondary-bg: #343a40;
|
||||
--bs-secondary-bg-rgb: 52, 58, 64;
|
||||
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
|
||||
--bs-tertiary-color-rgb: 222, 226, 230;
|
||||
--bs-tertiary-bg: #2b3035;
|
||||
--bs-tertiary-bg-rgb: 43, 48, 53;
|
||||
--bs-primary-text-emphasis: #6ea8fe;
|
||||
--bs-secondary-text-emphasis: #a7acb1;
|
||||
--bs-success-text-emphasis: #75b798;
|
||||
--bs-info-text-emphasis: #6edff6;
|
||||
--bs-warning-text-emphasis: #ffda6a;
|
||||
--bs-danger-text-emphasis: #ea868f;
|
||||
--bs-light-text-emphasis: #f8f9fa;
|
||||
--bs-dark-text-emphasis: #dee2e6;
|
||||
--bs-primary-bg-subtle: #031633;
|
||||
--bs-secondary-bg-subtle: #161719;
|
||||
--bs-success-bg-subtle: #051b11;
|
||||
--bs-info-bg-subtle: #032830;
|
||||
--bs-warning-bg-subtle: #332701;
|
||||
--bs-danger-bg-subtle: #2c0b0e;
|
||||
--bs-light-bg-subtle: #343a40;
|
||||
--bs-dark-bg-subtle: #1a1d20;
|
||||
--bs-primary-border-subtle: #084298;
|
||||
--bs-secondary-border-subtle: #41464b;
|
||||
--bs-success-border-subtle: #0f5132;
|
||||
--bs-info-border-subtle: #087990;
|
||||
--bs-warning-border-subtle: #997404;
|
||||
--bs-danger-border-subtle: #842029;
|
||||
--bs-light-border-subtle: #495057;
|
||||
--bs-dark-border-subtle: #343a40;
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: #6ea8fe;
|
||||
--bs-link-hover-color: #8bb9fe;
|
||||
--bs-link-color-rgb: 110, 168, 254;
|
||||
--bs-link-hover-color-rgb: 139, 185, 254;
|
||||
--bs-code-color: #e685b5;
|
||||
--bs-highlight-color: #dee2e6;
|
||||
--bs-highlight-bg: #664d03;
|
||||
--bs-border-color: #495057;
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
|
||||
--bs-form-valid-color: #75b798;
|
||||
--bs-form-valid-border-color: #75b798;
|
||||
--bs-form-invalid-color: #ea868f;
|
||||
--bs-form-invalid-border-color: #ea868f;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
border: 0;
|
||||
border-top: var(--bs-border-width) solid;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
color: var(--bs-heading-color);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.1875em;
|
||||
color: var(--bs-highlight-color);
|
||||
background-color: var(--bs-highlight-bg);
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-code-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.1875rem 0.375rem;
|
||||
font-size: 0.875em;
|
||||
color: var(--bs-body-bg);
|
||||
background-color: var(--bs-body-color);
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: var(--bs-secondary-color);
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: right;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
-webkit-appearance: textfield;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */
|
||||
1
static/bootstrap5/css/bootstrap-reboot.rtl.css.map
Normal file
1
static/bootstrap5/css/bootstrap-reboot.rtl.css.map
Normal file
File diff suppressed because one or more lines are too long
6
static/bootstrap5/css/bootstrap-reboot.rtl.min.css
vendored
Normal file
6
static/bootstrap5/css/bootstrap-reboot.rtl.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/bootstrap5/css/bootstrap-reboot.rtl.min.css.map
Normal file
1
static/bootstrap5/css/bootstrap-reboot.rtl.min.css.map
Normal file
File diff suppressed because one or more lines are too long
5402
static/bootstrap5/css/bootstrap-utilities.css
vendored
Normal file
5402
static/bootstrap5/css/bootstrap-utilities.css
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
static/bootstrap5/css/bootstrap-utilities.css.map
Normal file
1
static/bootstrap5/css/bootstrap-utilities.css.map
Normal file
File diff suppressed because one or more lines are too long
6
static/bootstrap5/css/bootstrap-utilities.min.css
vendored
Normal file
6
static/bootstrap5/css/bootstrap-utilities.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/bootstrap5/css/bootstrap-utilities.min.css.map
Normal file
1
static/bootstrap5/css/bootstrap-utilities.min.css.map
Normal file
File diff suppressed because one or more lines are too long
5393
static/bootstrap5/css/bootstrap-utilities.rtl.css
vendored
Normal file
5393
static/bootstrap5/css/bootstrap-utilities.rtl.css
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
static/bootstrap5/css/bootstrap-utilities.rtl.css.map
Normal file
1
static/bootstrap5/css/bootstrap-utilities.rtl.css.map
Normal file
File diff suppressed because one or more lines are too long
6
static/bootstrap5/css/bootstrap-utilities.rtl.min.css
vendored
Normal file
6
static/bootstrap5/css/bootstrap-utilities.rtl.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
12057
static/bootstrap5/css/bootstrap.css
vendored
Normal file
12057
static/bootstrap5/css/bootstrap.css
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
static/bootstrap5/css/bootstrap.css.map
Normal file
1
static/bootstrap5/css/bootstrap.css.map
Normal file
File diff suppressed because one or more lines are too long
6
static/bootstrap5/css/bootstrap.min.css
vendored
Normal file
6
static/bootstrap5/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/bootstrap5/css/bootstrap.min.css.map
Normal file
1
static/bootstrap5/css/bootstrap.min.css.map
Normal file
File diff suppressed because one or more lines are too long
12030
static/bootstrap5/css/bootstrap.rtl.css
vendored
Normal file
12030
static/bootstrap5/css/bootstrap.rtl.css
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
static/bootstrap5/css/bootstrap.rtl.css.map
Normal file
1
static/bootstrap5/css/bootstrap.rtl.css.map
Normal file
File diff suppressed because one or more lines are too long
6
static/bootstrap5/css/bootstrap.rtl.min.css
vendored
Normal file
6
static/bootstrap5/css/bootstrap.rtl.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/bootstrap5/css/bootstrap.rtl.min.css.map
Normal file
1
static/bootstrap5/css/bootstrap.rtl.min.css.map
Normal file
File diff suppressed because one or more lines are too long
6314
static/bootstrap5/js/bootstrap.bundle.js
vendored
Normal file
6314
static/bootstrap5/js/bootstrap.bundle.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
static/bootstrap5/js/bootstrap.bundle.js.map
Normal file
1
static/bootstrap5/js/bootstrap.bundle.js.map
Normal file
File diff suppressed because one or more lines are too long
7
static/bootstrap5/js/bootstrap.bundle.min.js
vendored
Normal file
7
static/bootstrap5/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/bootstrap5/js/bootstrap.bundle.min.js.map
Normal file
1
static/bootstrap5/js/bootstrap.bundle.min.js.map
Normal file
File diff suppressed because one or more lines are too long
4447
static/bootstrap5/js/bootstrap.esm.js
vendored
Normal file
4447
static/bootstrap5/js/bootstrap.esm.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
static/bootstrap5/js/bootstrap.esm.js.map
Normal file
1
static/bootstrap5/js/bootstrap.esm.js.map
Normal file
File diff suppressed because one or more lines are too long
7
static/bootstrap5/js/bootstrap.esm.min.js
vendored
Normal file
7
static/bootstrap5/js/bootstrap.esm.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/bootstrap5/js/bootstrap.esm.min.js.map
Normal file
1
static/bootstrap5/js/bootstrap.esm.min.js.map
Normal file
File diff suppressed because one or more lines are too long
4494
static/bootstrap5/js/bootstrap.js
vendored
Normal file
4494
static/bootstrap5/js/bootstrap.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
static/bootstrap5/js/bootstrap.js.map
Normal file
1
static/bootstrap5/js/bootstrap.js.map
Normal file
File diff suppressed because one or more lines are too long
7
static/bootstrap5/js/bootstrap.min.js
vendored
Normal file
7
static/bootstrap5/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/bootstrap5/js/bootstrap.min.js.map
Normal file
1
static/bootstrap5/js/bootstrap.min.js.map
Normal file
File diff suppressed because one or more lines are too long
1061
static/es-module-shims/es-module-shims.debug.js
Normal file
1061
static/es-module-shims/es-module-shims.debug.js
Normal file
File diff suppressed because one or more lines are too long
1049
static/es-module-shims/es-module-shims.js
Normal file
1049
static/es-module-shims/es-module-shims.js
Normal file
File diff suppressed because one or more lines are too long
1049
static/es-module-shims/es-module-shims.wasm.js
Normal file
1049
static/es-module-shims/es-module-shims.wasm.js
Normal file
File diff suppressed because one or more lines are too long
270
static/leaflet-geodesic/leaflet.geodesic.d.ts
vendored
Normal file
270
static/leaflet-geodesic/leaflet.geodesic.d.ts
vendored
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
/*! leaflet.geodesic 2.7.1 - (c) Henry Thasler - https://github.com/henrythasler/Leaflet.Geodesic#readme */
|
||||
import * as L from 'leaflet';
|
||||
|
||||
interface GeodesicOptions extends L.PolylineOptions {
|
||||
wrap?: boolean;
|
||||
steps?: number;
|
||||
radius?: number;
|
||||
}
|
||||
interface WGS84Vector extends L.LatLngLiteral {
|
||||
bearing: number;
|
||||
}
|
||||
interface GeoDistance {
|
||||
distance: number;
|
||||
initialBearing: number;
|
||||
finalBearing: number;
|
||||
}
|
||||
declare class GeodesicCore {
|
||||
readonly options: GeodesicOptions;
|
||||
readonly ellipsoid: {
|
||||
a: number;
|
||||
b: number;
|
||||
f: number;
|
||||
};
|
||||
constructor(options?: GeodesicOptions);
|
||||
toRadians(degree: number): number;
|
||||
toDegrees(radians: number): number;
|
||||
/**
|
||||
* implements scientific modulus
|
||||
* source: http://www.codeavenger.com/2017/05/19/JavaScript-Modulo-operation-and-the-Caesar-Cipher.html
|
||||
* @param n
|
||||
* @param p
|
||||
* @return
|
||||
*/
|
||||
mod(n: number, p: number): number;
|
||||
/**
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/dms.js
|
||||
* @param degrees arbitrary value
|
||||
* @return degrees between 0..360
|
||||
*/
|
||||
wrap360(degrees: number): number;
|
||||
/**
|
||||
* general wrap function with arbitrary max value
|
||||
* @param degrees arbitrary value
|
||||
* @param max
|
||||
* @return degrees between `-max`..`+max`
|
||||
*/
|
||||
wrap(degrees: number, max?: number): number;
|
||||
/**
|
||||
* Vincenty direct calculation.
|
||||
* based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/latlon-ellipsoidal-vincenty.js
|
||||
*
|
||||
* @param start starting point
|
||||
* @param bearing initial bearing (in degrees)
|
||||
* @param distance distance from starting point to calculate along given bearing in meters.
|
||||
* @param maxInterations How many iterations can be made to reach the allowed deviation (`ε`), before an error will be thrown.
|
||||
* @return Final point (destination point) and bearing (in degrees)
|
||||
*/
|
||||
direct(start: L.LatLng, bearing: number, distance: number, maxInterations?: number): WGS84Vector;
|
||||
/**
|
||||
* Vincenty inverse calculation.
|
||||
* based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/latlon-ellipsoidal-vincenty.js
|
||||
*
|
||||
* @param start Latitude/longitude of starting point.
|
||||
* @param dest Latitude/longitude of destination point.
|
||||
* @return Object including distance, initialBearing, finalBearing.
|
||||
*/
|
||||
inverse(start: L.LatLng, dest: L.LatLng, maxInterations?: number, mitigateConvergenceError?: boolean): GeoDistance;
|
||||
/**
|
||||
* Returns the point of intersection of two paths defined by position and bearing.
|
||||
* This calculation uses a spherical model of the earth. This will lead to small errors compared to an ellipsiod model.
|
||||
* based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js
|
||||
*
|
||||
* @param firstPos 1st path: position and bearing
|
||||
* @param firstBearing
|
||||
* @param secondPos 2nd path: position and bearing
|
||||
* @param secondBearing
|
||||
*/
|
||||
intersection(firstPos: L.LatLng, firstBearing: number, secondPos: L.LatLng, secondBearing: number): L.LatLng | null;
|
||||
midpoint(start: L.LatLng, dest: L.LatLng): L.LatLng;
|
||||
}
|
||||
|
||||
/** detailled information of the current geometry */
|
||||
interface Statistics {
|
||||
/** Stores the distance for each individual geodesic line */
|
||||
distanceArray: number[];
|
||||
/** overall distance of all lines */
|
||||
totalDistance: number;
|
||||
/** number of positions that the geodesic lines are created from */
|
||||
points: number;
|
||||
/** number vertices that were created during geometry calculation */
|
||||
vertices: number;
|
||||
}
|
||||
declare class GeodesicGeometry {
|
||||
readonly geodesic: GeodesicCore;
|
||||
steps: number;
|
||||
constructor(options?: GeodesicOptions);
|
||||
/**
|
||||
* A geodesic line between `start` and `dest` is created with this recursive function.
|
||||
* It calculates the geodesic midpoint between `start` and `dest` and uses this midpoint to call itself again (twice!).
|
||||
* The results are then merged into one continuous linestring.
|
||||
*
|
||||
* The number of resulting vertices (incl. `start` and `dest`) depends on the initial value for `iterations`
|
||||
* and can be calculated with: vertices == 1 + 2 ** (initialIterations + 1)
|
||||
*
|
||||
* As this is an exponential function, be extra careful to limit the initial value for `iterations` (8 results in 513 vertices).
|
||||
*
|
||||
* @param start start position
|
||||
* @param dest destination
|
||||
* @param iterations
|
||||
* @return resulting linestring
|
||||
*/
|
||||
recursiveMidpoint(start: L.LatLng, dest: L.LatLng, iterations: number): L.LatLng[];
|
||||
/**
|
||||
* This is the wrapper-function to generate a geodesic line. It's just for future backwards-compatibility
|
||||
* if there is another algorithm used to create the actual line.
|
||||
*
|
||||
* The `steps`-property is used to define the number of resulting vertices of the linestring: vertices == 1 + 2 ** (steps + 1)
|
||||
* The value for `steps` is currently limited to 8 (513 vertices) for performance reasons until another algorithm is found.
|
||||
*
|
||||
* @param start start position
|
||||
* @param dest destination
|
||||
* @return resulting linestring
|
||||
*/
|
||||
line(start: L.LatLng, dest: L.LatLng): L.LatLng[];
|
||||
multiLineString(latlngs: L.LatLng[][]): L.LatLng[][];
|
||||
lineString(latlngs: L.LatLng[]): L.LatLng[];
|
||||
/**
|
||||
*
|
||||
* Is much (10x) faster than the previous implementation:
|
||||
*
|
||||
* ```
|
||||
* Benchmark (no split): splitLine x 459,044 ops/sec ±0.53% (95 runs sampled)
|
||||
* Benchmark (split): splitLine x 42,999 ops/sec ±0.51% (97 runs sampled)
|
||||
* ```
|
||||
*
|
||||
* @param startPosition
|
||||
* @param destPosition
|
||||
*/
|
||||
splitLine(startPosition: L.LatLng, destPosition: L.LatLng): L.LatLng[][];
|
||||
/**
|
||||
* Linestrings of a given multilinestring that cross the antimeridian will be split in two separate linestrings.
|
||||
* This function is used to wrap lines around when they cross the antimeridian
|
||||
* It iterates over all linestrings and reconstructs the step-by-step if no split is needed.
|
||||
* In case the line was split, the linestring ends at the antimeridian and a new linestring is created for the
|
||||
* remaining points of the original linestring.
|
||||
*
|
||||
* @param multilinestring
|
||||
* @return another multilinestring where segments crossing the antimeridian are split
|
||||
*/
|
||||
splitMultiLineString(multilinestring: L.LatLng[][]): L.LatLng[][];
|
||||
/**
|
||||
* Linestrings of a given multilinestring will be wrapped (+- 360°) to show a continuous line w/o any weird discontinuities
|
||||
* when `wrap` is set to `false` in the geodesic class
|
||||
* @param multilinestring
|
||||
* @returns another multilinestring where the points of each linestring are wrapped accordingly
|
||||
*/
|
||||
wrapMultiLineString(multilinestring: L.LatLng[][]): L.LatLng[][];
|
||||
/**
|
||||
* Creates a circular (constant radius), closed (1st pos == last pos) geodesic linestring.
|
||||
* The number of vertices is calculated with: `vertices == steps + 1` (where 1st == last)
|
||||
*
|
||||
* @param center
|
||||
* @param radius
|
||||
* @return resulting linestring
|
||||
*/
|
||||
circle(center: L.LatLng, radius: number): L.LatLng[];
|
||||
/**
|
||||
* Handles splitting of circles at the antimeridian.
|
||||
* @param linestring a linestring that resembles the geodesic circle
|
||||
* @return a multilinestring that consist of one or two linestrings
|
||||
*/
|
||||
splitCircle(linestring: L.LatLng[]): L.LatLng[][];
|
||||
/**
|
||||
* Calculates the distance between two positions on the earths surface
|
||||
* @param start 1st position
|
||||
* @param dest 2nd position
|
||||
* @return the distance in **meters**
|
||||
*/
|
||||
distance(start: L.LatLng, dest: L.LatLng): number;
|
||||
multilineDistance(multilinestring: L.LatLng[][]): number[];
|
||||
updateStatistics(points: L.LatLng[][], vertices: L.LatLng[][]): Statistics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw geodesic lines based on L.Polyline
|
||||
*/
|
||||
declare class GeodesicLine extends L.Polyline {
|
||||
/** these should be good for most use-cases */
|
||||
defaultOptions: GeodesicOptions;
|
||||
/** does the actual geometry calculations */
|
||||
readonly geom: GeodesicGeometry;
|
||||
/** use this if you need some detailled info about the current geometry */
|
||||
statistics: Statistics;
|
||||
/** stores all positions that are used to create the geodesic line */
|
||||
points: L.LatLng[][];
|
||||
constructor(latlngs?: L.LatLngExpression[] | L.LatLngExpression[][], options?: GeodesicOptions);
|
||||
/** calculates the geodesics and update the polyline-object accordingly */
|
||||
private updateGeometry;
|
||||
/**
|
||||
* overwrites the original function with additional functionality to create a geodesic line
|
||||
* @param latlngs an array (or 2d-array) of positions
|
||||
*/
|
||||
setLatLngs(latlngs: L.LatLngExpression[] | L.LatLngExpression[][]): this;
|
||||
/**
|
||||
* add a given point to the geodesic line object
|
||||
* @param latlng point to add. The point will always be added to the last linestring of a multiline
|
||||
* @param latlngs define a linestring to add the new point to. Read from points-property before (e.g. `line.addLatLng(Beijing, line.points[0]);`)
|
||||
*/
|
||||
addLatLng(latlng: L.LatLngExpression, latlngs?: L.LatLng[]): this;
|
||||
/**
|
||||
* Creates geodesic lines from a given GeoJSON-Object.
|
||||
* @param input GeoJSON-Object
|
||||
*/
|
||||
fromGeoJson(input: GeoJSON.GeoJSON): this;
|
||||
/**
|
||||
* Calculates the distance between two geo-positions
|
||||
* @param start 1st position
|
||||
* @param dest 2nd position
|
||||
* @return the distance in meters
|
||||
*/
|
||||
distance(start: L.LatLngExpression, dest: L.LatLngExpression): number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to create a geodesic circle based on L.Polyline
|
||||
*/
|
||||
declare class GeodesicCircleClass extends L.Polyline {
|
||||
defaultOptions: GeodesicOptions;
|
||||
readonly geom: GeodesicGeometry;
|
||||
center: L.LatLng;
|
||||
radius: number;
|
||||
statistics: Statistics;
|
||||
constructor(center?: L.LatLngExpression, options?: GeodesicOptions);
|
||||
/**
|
||||
* Updates the geometry and re-calculates some statistics
|
||||
*/
|
||||
private update;
|
||||
/**
|
||||
* Calculate the distance between the current center and an arbitrary position.
|
||||
* @param latlng geo-position to calculate distance to
|
||||
* @return distance in meters
|
||||
*/
|
||||
distanceTo(latlng: L.LatLngExpression): number;
|
||||
/**
|
||||
* Set a new center for the geodesic circle and update the geometry. Radius may also be set.
|
||||
* @param center the new center
|
||||
* @param radius the new radius
|
||||
*/
|
||||
setLatLng(center: L.LatLngExpression, radius?: number): void;
|
||||
/**
|
||||
* Set a new radius for the geodesic circle and update the geometry. Center may also be set.
|
||||
* @param radius the new radius
|
||||
* @param center the new center
|
||||
*/
|
||||
setRadius(radius: number, center?: L.LatLngExpression): void;
|
||||
}
|
||||
|
||||
declare module "leaflet" {
|
||||
type Geodesic = GeodesicLine;
|
||||
let Geodesic: typeof GeodesicLine;
|
||||
let geodesic: (...args: ConstructorParameters<typeof GeodesicLine>) => GeodesicLine;
|
||||
type GeodesicCircle = GeodesicCircleClass;
|
||||
let GeodesicCircle: typeof GeodesicCircleClass;
|
||||
let geodesiccircle: (...args: ConstructorParameters<typeof GeodesicCircleClass>) => GeodesicCircleClass;
|
||||
}
|
||||
|
||||
export { GeodesicCircleClass, GeodesicLine };
|
||||
895
static/leaflet-geodesic/leaflet.geodesic.esm.js
Normal file
895
static/leaflet-geodesic/leaflet.geodesic.esm.js
Normal file
|
|
@ -0,0 +1,895 @@
|
|||
/*! leaflet.geodesic 2.7.1 - (c) Henry Thasler - https://github.com/henrythasler/Leaflet.Geodesic#readme */
|
||||
import * as L from 'leaflet';
|
||||
|
||||
/******************************************************************************
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
***************************************************************************** */
|
||||
/* global Reflect, Promise, SuppressedError, Symbol */
|
||||
|
||||
var extendStatics = function(d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
|
||||
function __extends(d, b) {
|
||||
if (typeof b !== "function" && b !== null)
|
||||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
}
|
||||
|
||||
var __assign = function() {
|
||||
__assign = Object.assign || function __assign(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
|
||||
function __spreadArray(to, from, pack) {
|
||||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
||||
if (ar || !(i in from)) {
|
||||
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
||||
ar[i] = from[i];
|
||||
}
|
||||
}
|
||||
return to.concat(ar || Array.prototype.slice.call(from));
|
||||
}
|
||||
|
||||
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
||||
var e = new Error(message);
|
||||
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
||||
};
|
||||
|
||||
var GeodesicCore = /** @class */ (function () {
|
||||
function GeodesicCore(options) {
|
||||
this.options = { wrap: true, steps: 3 };
|
||||
this.ellipsoid = {
|
||||
a: 6378137,
|
||||
b: 6356752.3142,
|
||||
f: 1 / 298.257223563
|
||||
}; // WGS-84
|
||||
this.options = __assign(__assign({}, this.options), options);
|
||||
}
|
||||
GeodesicCore.prototype.toRadians = function (degree) {
|
||||
return (degree * Math.PI) / 180;
|
||||
};
|
||||
GeodesicCore.prototype.toDegrees = function (radians) {
|
||||
return (radians * 180) / Math.PI;
|
||||
};
|
||||
/**
|
||||
* implements scientific modulus
|
||||
* source: http://www.codeavenger.com/2017/05/19/JavaScript-Modulo-operation-and-the-Caesar-Cipher.html
|
||||
* @param n
|
||||
* @param p
|
||||
* @return
|
||||
*/
|
||||
GeodesicCore.prototype.mod = function (n, p) {
|
||||
var r = n % p;
|
||||
return r < 0 ? r + p : r;
|
||||
};
|
||||
/**
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/dms.js
|
||||
* @param degrees arbitrary value
|
||||
* @return degrees between 0..360
|
||||
*/
|
||||
GeodesicCore.prototype.wrap360 = function (degrees) {
|
||||
if (0 <= degrees && degrees < 360) {
|
||||
return degrees; // avoid rounding due to arithmetic ops if within range
|
||||
}
|
||||
else {
|
||||
return this.mod(degrees, 360);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* general wrap function with arbitrary max value
|
||||
* @param degrees arbitrary value
|
||||
* @param max
|
||||
* @return degrees between `-max`..`+max`
|
||||
*/
|
||||
GeodesicCore.prototype.wrap = function (degrees, max) {
|
||||
if (max === void 0) { max = 360; }
|
||||
if (-max <= degrees && degrees <= max) {
|
||||
return degrees;
|
||||
}
|
||||
else {
|
||||
return this.mod(degrees + max, 2 * max) - max;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Vincenty direct calculation.
|
||||
* based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/latlon-ellipsoidal-vincenty.js
|
||||
*
|
||||
* @param start starting point
|
||||
* @param bearing initial bearing (in degrees)
|
||||
* @param distance distance from starting point to calculate along given bearing in meters.
|
||||
* @param maxInterations How many iterations can be made to reach the allowed deviation (`ε`), before an error will be thrown.
|
||||
* @return Final point (destination point) and bearing (in degrees)
|
||||
*/
|
||||
GeodesicCore.prototype.direct = function (start, bearing, distance, maxInterations) {
|
||||
if (maxInterations === void 0) { maxInterations = 100; }
|
||||
var φ1 = this.toRadians(start.lat);
|
||||
var λ1 = this.toRadians(start.lng);
|
||||
var α1 = this.toRadians(bearing);
|
||||
var s = distance;
|
||||
var ε = Number.EPSILON * 1000;
|
||||
var _a = this.ellipsoid, a = _a.a, b = _a.b, f = _a.f;
|
||||
var sinα1 = Math.sin(α1);
|
||||
var cosα1 = Math.cos(α1);
|
||||
var tanU1 = (1 - f) * Math.tan(φ1), cosU1 = 1 / Math.sqrt(1 + tanU1 * tanU1), sinU1 = tanU1 * cosU1;
|
||||
var σ1 = Math.atan2(tanU1, cosα1); // σ1 = angular distance on the sphere from the equator to P1
|
||||
var sinα = cosU1 * sinα1; // α = azimuth of the geodesic at the equator
|
||||
var cosSqα = 1 - sinα * sinα;
|
||||
var uSq = (cosSqα * (a * a - b * b)) / (b * b);
|
||||
var A = 1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
|
||||
var B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
|
||||
var σ = s / (b * A), sinσ = null, cosσ = null, Δσ = null; // σ = angular distance P₁ P₂ on the sphere
|
||||
var cos2σₘ = null; // σₘ = angular distance on the sphere from the equator to the midpoint of the line
|
||||
var σʹ = null, iterations = 0;
|
||||
do {
|
||||
cos2σₘ = Math.cos(2 * σ1 + σ);
|
||||
sinσ = Math.sin(σ);
|
||||
cosσ = Math.cos(σ);
|
||||
Δσ =
|
||||
B *
|
||||
sinσ *
|
||||
(cos2σₘ +
|
||||
(B / 4) *
|
||||
(cosσ * (-1 + 2 * cos2σₘ * cos2σₘ) -
|
||||
(B / 6) * cos2σₘ * (-3 + 4 * sinσ * sinσ) * (-3 + 4 * cos2σₘ * cos2σₘ)));
|
||||
σʹ = σ;
|
||||
σ = s / (b * A) + Δσ;
|
||||
} while (Math.abs(σ - σʹ) > ε && ++iterations < maxInterations);
|
||||
if (iterations >= maxInterations) {
|
||||
throw new EvalError("Direct vincenty formula failed to converge after ".concat(maxInterations, " iterations \n (start=").concat(start.lat, "/").concat(start.lng, "; bearing=").concat(bearing, "; distance=").concat(distance, ")")); // not possible?
|
||||
}
|
||||
var x = sinU1 * sinσ - cosU1 * cosσ * cosα1;
|
||||
var φ2 = Math.atan2(sinU1 * cosσ + cosU1 * sinσ * cosα1, (1 - f) * Math.sqrt(sinα * sinα + x * x));
|
||||
var λ = Math.atan2(sinσ * sinα1, cosU1 * cosσ - sinU1 * sinσ * cosα1);
|
||||
var C = (f / 16) * cosSqα * (4 + f * (4 - 3 * cosSqα));
|
||||
var dL = λ - (1 - C) * f * sinα * (σ + C * sinσ * (cos2σₘ + C * cosσ * (-1 + 2 * cos2σₘ * cos2σₘ)));
|
||||
var λ2 = λ1 + dL;
|
||||
var α2 = Math.atan2(sinα, -x);
|
||||
return {
|
||||
lat: this.toDegrees(φ2),
|
||||
lng: this.toDegrees(λ2),
|
||||
bearing: this.wrap360(this.toDegrees(α2))
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Vincenty inverse calculation.
|
||||
* based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/latlon-ellipsoidal-vincenty.js
|
||||
*
|
||||
* @param start Latitude/longitude of starting point.
|
||||
* @param dest Latitude/longitude of destination point.
|
||||
* @return Object including distance, initialBearing, finalBearing.
|
||||
*/
|
||||
GeodesicCore.prototype.inverse = function (start, dest, maxInterations, mitigateConvergenceError) {
|
||||
if (maxInterations === void 0) { maxInterations = 100; }
|
||||
if (mitigateConvergenceError === void 0) { mitigateConvergenceError = true; }
|
||||
var p1 = start, p2 = dest;
|
||||
var φ1 = this.toRadians(p1.lat), λ1 = this.toRadians(p1.lng);
|
||||
var φ2 = this.toRadians(p2.lat), λ2 = this.toRadians(p2.lng);
|
||||
var π = Math.PI;
|
||||
var ε = Number.EPSILON;
|
||||
// allow alternative ellipsoid to be specified
|
||||
var _a = this.ellipsoid, a = _a.a, b = _a.b, f = _a.f;
|
||||
var dL = λ2 - λ1; // L = difference in longitude, U = reduced latitude, defined by tan U = (1-f)·tanφ.
|
||||
var tanU1 = (1 - f) * Math.tan(φ1), cosU1 = 1 / Math.sqrt(1 + tanU1 * tanU1), sinU1 = tanU1 * cosU1;
|
||||
var tanU2 = (1 - f) * Math.tan(φ2), cosU2 = 1 / Math.sqrt(1 + tanU2 * tanU2), sinU2 = tanU2 * cosU2;
|
||||
var antipodal = Math.abs(dL) > π / 2 || Math.abs(φ2 - φ1) > π / 2;
|
||||
var λ = dL, sinλ = null, cosλ = null; // λ = difference in longitude on an auxiliary sphere
|
||||
var σ = antipodal ? π : 0, sinσ = 0, cosσ = antipodal ? -1 : 1, sinSqσ = null; // σ = angular distance P₁ P₂ on the sphere
|
||||
var cos2σₘ = 1; // σₘ = angular distance on the sphere from the equator to the midpoint of the line
|
||||
var sinα = null, cosSqα = 1; // α = azimuth of the geodesic at the equator
|
||||
var C = null;
|
||||
var λʹ = null, iterations = 0;
|
||||
do {
|
||||
sinλ = Math.sin(λ);
|
||||
cosλ = Math.cos(λ);
|
||||
sinSqσ =
|
||||
cosU2 * sinλ * (cosU2 * sinλ) +
|
||||
(cosU1 * sinU2 - sinU1 * cosU2 * cosλ) * (cosU1 * sinU2 - sinU1 * cosU2 * cosλ);
|
||||
if (Math.abs(sinSqσ) < ε) {
|
||||
break; // co-incident/antipodal points (falls back on λ/σ = L)
|
||||
}
|
||||
sinσ = Math.sqrt(sinSqσ);
|
||||
cosσ = sinU1 * sinU2 + cosU1 * cosU2 * cosλ;
|
||||
σ = Math.atan2(sinσ, cosσ);
|
||||
sinα = (cosU1 * cosU2 * sinλ) / sinσ;
|
||||
cosSqα = 1 - sinα * sinα;
|
||||
cos2σₘ = cosSqα !== 0 ? cosσ - (2 * sinU1 * sinU2) / cosSqα : 0; // on equatorial line cos²α = 0 (§6)
|
||||
C = (f / 16) * cosSqα * (4 + f * (4 - 3 * cosSqα));
|
||||
λʹ = λ;
|
||||
λ = dL + (1 - C) * f * sinα * (σ + C * sinσ * (cos2σₘ + C * cosσ * (-1 + 2 * cos2σₘ * cos2σₘ)));
|
||||
var iterationCheck = antipodal ? Math.abs(λ) - π : Math.abs(λ);
|
||||
if (iterationCheck > π) {
|
||||
throw new EvalError("λ > π");
|
||||
}
|
||||
} while (Math.abs(λ - λʹ) > 1e-12 && ++iterations < maxInterations);
|
||||
if (iterations >= maxInterations) {
|
||||
if (mitigateConvergenceError) {
|
||||
return this.inverse(start, new L.LatLng(dest.lat, dest.lng - 0.01), maxInterations, mitigateConvergenceError);
|
||||
}
|
||||
else {
|
||||
throw new EvalError("Inverse vincenty formula failed to converge after ".concat(maxInterations, " iterations \n (start=").concat(start.lat, "/").concat(start.lng, "; dest=").concat(dest.lat, "/").concat(dest.lng, ")"));
|
||||
}
|
||||
}
|
||||
var uSq = (cosSqα * (a * a - b * b)) / (b * b);
|
||||
var A = 1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
|
||||
var B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
|
||||
var Δσ = B *
|
||||
sinσ *
|
||||
(cos2σₘ +
|
||||
(B / 4) *
|
||||
(cosσ * (-1 + 2 * cos2σₘ * cos2σₘ) -
|
||||
(B / 6) * cos2σₘ * (-3 + 4 * sinσ * sinσ) * (-3 + 4 * cos2σₘ * cos2σₘ)));
|
||||
var s = b * A * (σ - Δσ); // s = length of the geodesic
|
||||
// note special handling of exactly antipodal points where sin²σ = 0 (due to discontinuity
|
||||
// atan2(0, 0) = 0 but atan2(this.ε, 0) = π/2 / 90°) - in which case bearing is always meridional,
|
||||
// due north (or due south!)
|
||||
// α = azimuths of the geodesic; α2 the direction P₁ P₂ produced
|
||||
var α1 = Math.abs(sinSqσ) < ε ? 0 : Math.atan2(cosU2 * sinλ, cosU1 * sinU2 - sinU1 * cosU2 * cosλ);
|
||||
var α2 = Math.abs(sinSqσ) < ε ? π : Math.atan2(cosU1 * sinλ, -sinU1 * cosU2 + cosU1 * sinU2 * cosλ);
|
||||
return {
|
||||
distance: s,
|
||||
initialBearing: Math.abs(s) < ε ? NaN : this.wrap360(this.toDegrees(α1)),
|
||||
finalBearing: Math.abs(s) < ε ? NaN : this.wrap360(this.toDegrees(α2))
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Returns the point of intersection of two paths defined by position and bearing.
|
||||
* This calculation uses a spherical model of the earth. This will lead to small errors compared to an ellipsiod model.
|
||||
* based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js
|
||||
*
|
||||
* @param firstPos 1st path: position and bearing
|
||||
* @param firstBearing
|
||||
* @param secondPos 2nd path: position and bearing
|
||||
* @param secondBearing
|
||||
*/
|
||||
GeodesicCore.prototype.intersection = function (firstPos, firstBearing, secondPos, secondBearing) {
|
||||
var φ1 = this.toRadians(firstPos.lat);
|
||||
var λ1 = this.toRadians(firstPos.lng);
|
||||
var φ2 = this.toRadians(secondPos.lat);
|
||||
var λ2 = this.toRadians(secondPos.lng);
|
||||
var θ13 = this.toRadians(firstBearing);
|
||||
var θ23 = this.toRadians(secondBearing);
|
||||
var Δφ = φ2 - φ1, Δλ = λ2 - λ1;
|
||||
var π = Math.PI;
|
||||
var ε = Number.EPSILON;
|
||||
// angular distance p1-p2
|
||||
var δ12 = 2 *
|
||||
Math.asin(Math.sqrt(Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
|
||||
Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2)));
|
||||
if (Math.abs(δ12) < ε) {
|
||||
return firstPos; // coincident points
|
||||
}
|
||||
// initial/final bearings between points
|
||||
var cosθa = (Math.sin(φ2) - Math.sin(φ1) * Math.cos(δ12)) / (Math.sin(δ12) * Math.cos(φ1));
|
||||
var cosθb = (Math.sin(φ1) - Math.sin(φ2) * Math.cos(δ12)) / (Math.sin(δ12) * Math.cos(φ2));
|
||||
var θa = Math.acos(Math.min(Math.max(cosθa, -1), 1)); // protect against rounding errors
|
||||
var θb = Math.acos(Math.min(Math.max(cosθb, -1), 1)); // protect against rounding errors
|
||||
var θ12 = Math.sin(λ2 - λ1) > 0 ? θa : 2 * π - θa;
|
||||
var θ21 = Math.sin(λ2 - λ1) > 0 ? 2 * π - θb : θb;
|
||||
var α1 = θ13 - θ12; // angle 2-1-3
|
||||
var α2 = θ21 - θ23; // angle 1-2-3
|
||||
if (Math.sin(α1) === 0 && Math.sin(α2) === 0) {
|
||||
return null; // infinite intersections
|
||||
}
|
||||
if (Math.sin(α1) * Math.sin(α2) < 0) {
|
||||
return null; // ambiguous intersection (antipodal?)
|
||||
}
|
||||
var cosα3 = -Math.cos(α1) * Math.cos(α2) + Math.sin(α1) * Math.sin(α2) * Math.cos(δ12);
|
||||
var δ13 = Math.atan2(Math.sin(δ12) * Math.sin(α1) * Math.sin(α2), Math.cos(α2) + Math.cos(α1) * cosα3);
|
||||
var φ3 = Math.asin(Math.min(Math.max(Math.sin(φ1) * Math.cos(δ13) + Math.cos(φ1) * Math.sin(δ13) * Math.cos(θ13), -1), 1));
|
||||
var Δλ13 = Math.atan2(Math.sin(θ13) * Math.sin(δ13) * Math.cos(φ1), Math.cos(δ13) - Math.sin(φ1) * Math.sin(φ3));
|
||||
var λ3 = λ1 + Δλ13;
|
||||
return new L.LatLng(this.toDegrees(φ3), this.toDegrees(λ3));
|
||||
};
|
||||
GeodesicCore.prototype.midpoint = function (start, dest) {
|
||||
// φm = atan2( sinφ1 + sinφ2, √( (cosφ1 + cosφ2⋅cosΔλ)² + cos²φ2⋅sin²Δλ ) )
|
||||
// λm = λ1 + atan2(cosφ2⋅sinΔλ, cosφ1 + cosφ2⋅cosΔλ)
|
||||
// midpoint is sum of vectors to two points: mathforum.org/library/drmath/view/51822.html
|
||||
var φ1 = this.toRadians(start.lat);
|
||||
var λ1 = this.toRadians(start.lng);
|
||||
var φ2 = this.toRadians(dest.lat);
|
||||
var Δλ = this.toRadians(dest.lng - start.lng);
|
||||
// get cartesian coordinates for the two points
|
||||
var A = { x: Math.cos(φ1), y: 0, z: Math.sin(φ1) }; // place point A on prime meridian y=0
|
||||
var B = { x: Math.cos(φ2) * Math.cos(Δλ), y: Math.cos(φ2) * Math.sin(Δλ), z: Math.sin(φ2) };
|
||||
// vector to midpoint is sum of vectors to two points (no need to normalise)
|
||||
var C = { x: A.x + B.x, y: A.y + B.y, z: A.z + B.z };
|
||||
var φm = Math.atan2(C.z, Math.sqrt(C.x * C.x + C.y * C.y));
|
||||
var λm = λ1 + Math.atan2(C.y, C.x);
|
||||
return new L.LatLng(this.toDegrees(φm), this.toDegrees(λm));
|
||||
};
|
||||
return GeodesicCore;
|
||||
}());
|
||||
|
||||
var GeodesicGeometry = /** @class */ (function () {
|
||||
function GeodesicGeometry(options) {
|
||||
var _a;
|
||||
this.geodesic = new GeodesicCore();
|
||||
this.steps = (_a = options === null || options === void 0 ? void 0 : options.steps) !== null && _a !== void 0 ? _a : 3;
|
||||
}
|
||||
/**
|
||||
* A geodesic line between `start` and `dest` is created with this recursive function.
|
||||
* It calculates the geodesic midpoint between `start` and `dest` and uses this midpoint to call itself again (twice!).
|
||||
* The results are then merged into one continuous linestring.
|
||||
*
|
||||
* The number of resulting vertices (incl. `start` and `dest`) depends on the initial value for `iterations`
|
||||
* and can be calculated with: vertices == 1 + 2 ** (initialIterations + 1)
|
||||
*
|
||||
* As this is an exponential function, be extra careful to limit the initial value for `iterations` (8 results in 513 vertices).
|
||||
*
|
||||
* @param start start position
|
||||
* @param dest destination
|
||||
* @param iterations
|
||||
* @return resulting linestring
|
||||
*/
|
||||
GeodesicGeometry.prototype.recursiveMidpoint = function (start, dest, iterations) {
|
||||
var geom = [start, dest];
|
||||
var midpoint = this.geodesic.midpoint(start, dest);
|
||||
if (iterations > 0) {
|
||||
geom.splice.apply(geom, __spreadArray([0, 1], this.recursiveMidpoint(start, midpoint, iterations - 1), false));
|
||||
geom.splice.apply(geom, __spreadArray([geom.length - 2, 2], this.recursiveMidpoint(midpoint, dest, iterations - 1), false));
|
||||
}
|
||||
else {
|
||||
geom.splice(1, 0, midpoint);
|
||||
}
|
||||
return geom;
|
||||
};
|
||||
/**
|
||||
* This is the wrapper-function to generate a geodesic line. It's just for future backwards-compatibility
|
||||
* if there is another algorithm used to create the actual line.
|
||||
*
|
||||
* The `steps`-property is used to define the number of resulting vertices of the linestring: vertices == 1 + 2 ** (steps + 1)
|
||||
* The value for `steps` is currently limited to 8 (513 vertices) for performance reasons until another algorithm is found.
|
||||
*
|
||||
* @param start start position
|
||||
* @param dest destination
|
||||
* @return resulting linestring
|
||||
*/
|
||||
GeodesicGeometry.prototype.line = function (start, dest) {
|
||||
return this.recursiveMidpoint(start, dest, Math.min(8, this.steps));
|
||||
};
|
||||
GeodesicGeometry.prototype.multiLineString = function (latlngs) {
|
||||
var multiLineString = [];
|
||||
for (var _i = 0, latlngs_1 = latlngs; _i < latlngs_1.length; _i++) {
|
||||
var linestring = latlngs_1[_i];
|
||||
var segment = [];
|
||||
for (var j = 1; j < linestring.length; j++) {
|
||||
segment.splice.apply(segment, __spreadArray([segment.length - 1, 1], this.line(linestring[j - 1], linestring[j]), false));
|
||||
}
|
||||
multiLineString.push(segment);
|
||||
}
|
||||
return multiLineString;
|
||||
};
|
||||
GeodesicGeometry.prototype.lineString = function (latlngs) {
|
||||
return this.multiLineString([latlngs])[0];
|
||||
};
|
||||
/**
|
||||
*
|
||||
* Is much (10x) faster than the previous implementation:
|
||||
*
|
||||
* ```
|
||||
* Benchmark (no split): splitLine x 459,044 ops/sec ±0.53% (95 runs sampled)
|
||||
* Benchmark (split): splitLine x 42,999 ops/sec ±0.51% (97 runs sampled)
|
||||
* ```
|
||||
*
|
||||
* @param startPosition
|
||||
* @param destPosition
|
||||
*/
|
||||
GeodesicGeometry.prototype.splitLine = function (startPosition, destPosition) {
|
||||
var antimeridianWest = {
|
||||
point: new L.LatLng(89.9, -180.0000001),
|
||||
bearing: 180
|
||||
};
|
||||
var antimeridianEast = {
|
||||
point: new L.LatLng(89.9, 180.0000001),
|
||||
bearing: 180
|
||||
};
|
||||
// make a copy to work with
|
||||
var start = new L.LatLng(startPosition.lat, startPosition.lng, startPosition.alt);
|
||||
var dest = new L.LatLng(destPosition.lat, destPosition.lng, destPosition.alt);
|
||||
start.lng = this.geodesic.wrap(start.lng, 360);
|
||||
dest.lng = this.geodesic.wrap(dest.lng, 360);
|
||||
if (dest.lng - start.lng > 180) {
|
||||
dest.lng = dest.lng - 360;
|
||||
}
|
||||
else if (dest.lng - start.lng < -180) {
|
||||
dest.lng = dest.lng + 360;
|
||||
}
|
||||
var result = [
|
||||
[
|
||||
new L.LatLng(start.lat, this.geodesic.wrap(start.lng, 180), start.alt),
|
||||
new L.LatLng(dest.lat, this.geodesic.wrap(dest.lng, 180), dest.alt)
|
||||
]
|
||||
];
|
||||
// crossing antimeridian from "this" side?
|
||||
if (start.lng >= -180 && start.lng <= 180) {
|
||||
// crossing the "western" antimeridian
|
||||
if (dest.lng < -180) {
|
||||
var bearing = this.geodesic.inverse(start, dest).initialBearing;
|
||||
var intersection = this.geodesic.intersection(start, bearing, antimeridianWest.point, antimeridianWest.bearing);
|
||||
if (intersection) {
|
||||
result = [
|
||||
[start, intersection],
|
||||
[
|
||||
new L.LatLng(intersection.lat, intersection.lng + 360),
|
||||
new L.LatLng(dest.lat, dest.lng + 360, dest.alt)
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
// crossing the "eastern" antimeridian
|
||||
else if (dest.lng > 180) {
|
||||
var bearing = this.geodesic.inverse(start, dest).initialBearing;
|
||||
var intersection = this.geodesic.intersection(start, bearing, antimeridianEast.point, antimeridianEast.bearing);
|
||||
if (intersection) {
|
||||
result = [
|
||||
[start, intersection],
|
||||
[
|
||||
new L.LatLng(intersection.lat, intersection.lng - 360),
|
||||
new L.LatLng(dest.lat, dest.lng - 360, dest.alt)
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
// coming back over the antimeridian from the "other" side?
|
||||
else if (dest.lng >= -180 && dest.lng <= 180) {
|
||||
// crossing the "western" antimeridian
|
||||
if (start.lng < -180) {
|
||||
var bearing = this.geodesic.inverse(start, dest).initialBearing;
|
||||
var intersection = this.geodesic.intersection(start, bearing, antimeridianWest.point, antimeridianWest.bearing);
|
||||
if (intersection) {
|
||||
result = [
|
||||
[
|
||||
new L.LatLng(start.lat, start.lng + 360, start.alt),
|
||||
new L.LatLng(intersection.lat, intersection.lng + 360)
|
||||
],
|
||||
[intersection, dest]
|
||||
];
|
||||
}
|
||||
}
|
||||
// crossing the "eastern" antimeridian
|
||||
else if (start.lng > 180) {
|
||||
var bearing = this.geodesic.inverse(start, dest).initialBearing;
|
||||
var intersection = this.geodesic.intersection(start, bearing, antimeridianWest.point, antimeridianWest.bearing);
|
||||
if (intersection) {
|
||||
result = [
|
||||
[
|
||||
new L.LatLng(start.lat, start.lng - 360, start.alt),
|
||||
new L.LatLng(intersection.lat, intersection.lng - 360)
|
||||
],
|
||||
[intersection, dest]
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/**
|
||||
* Linestrings of a given multilinestring that cross the antimeridian will be split in two separate linestrings.
|
||||
* This function is used to wrap lines around when they cross the antimeridian
|
||||
* It iterates over all linestrings and reconstructs the step-by-step if no split is needed.
|
||||
* In case the line was split, the linestring ends at the antimeridian and a new linestring is created for the
|
||||
* remaining points of the original linestring.
|
||||
*
|
||||
* @param multilinestring
|
||||
* @return another multilinestring where segments crossing the antimeridian are split
|
||||
*/
|
||||
GeodesicGeometry.prototype.splitMultiLineString = function (multilinestring) {
|
||||
var result = [];
|
||||
for (var _i = 0, multilinestring_1 = multilinestring; _i < multilinestring_1.length; _i++) {
|
||||
var linestring = multilinestring_1[_i];
|
||||
if (linestring.length === 1) {
|
||||
result.push(linestring); // just a single point in linestring, no need to split
|
||||
continue;
|
||||
}
|
||||
var segment = [];
|
||||
for (var j = 1; j < linestring.length; j++) {
|
||||
var split = this.splitLine(linestring[j - 1], linestring[j]);
|
||||
segment.pop();
|
||||
segment = segment.concat(split[0]);
|
||||
if (split.length > 1) {
|
||||
result.push(segment); // the line was split, so we end the linestring right here
|
||||
segment = split[1]; // begin the new linestring with the second part of the split line
|
||||
}
|
||||
}
|
||||
result.push(segment);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/**
|
||||
* Linestrings of a given multilinestring will be wrapped (+- 360°) to show a continuous line w/o any weird discontinuities
|
||||
* when `wrap` is set to `false` in the geodesic class
|
||||
* @param multilinestring
|
||||
* @returns another multilinestring where the points of each linestring are wrapped accordingly
|
||||
*/
|
||||
GeodesicGeometry.prototype.wrapMultiLineString = function (multilinestring) {
|
||||
var result = [];
|
||||
for (var _i = 0, multilinestring_2 = multilinestring; _i < multilinestring_2.length; _i++) {
|
||||
var linestring = multilinestring_2[_i];
|
||||
var resultLine = [];
|
||||
var previous = null;
|
||||
// iterate over every point and check if it needs to be wrapped
|
||||
for (var _a = 0, linestring_1 = linestring; _a < linestring_1.length; _a++) {
|
||||
var point = linestring_1[_a];
|
||||
if (previous === null) {
|
||||
// the first point is the anchor of the linestring from which the line will always start (w/o any wrapping applied)
|
||||
resultLine.push(new L.LatLng(point.lat, point.lng));
|
||||
previous = new L.LatLng(point.lat, point.lng);
|
||||
}
|
||||
else {
|
||||
// I prefer clearly defined branches over a continue-operation.
|
||||
// if the difference between the current and *previous* point is greater than 360°, the current point needs to be shifted
|
||||
// to be on the same 'sphere' as the previous one.
|
||||
var offset = Math.round((point.lng - previous.lng) / 360);
|
||||
// shift the point accordingly and add to the result
|
||||
resultLine.push(new L.LatLng(point.lat, point.lng - offset * 360));
|
||||
// use the wrapped point as the anchor for the next one
|
||||
previous = new L.LatLng(point.lat, point.lng - offset * 360); // Need a new object here, to avoid changing the input data
|
||||
}
|
||||
}
|
||||
result.push(resultLine);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/**
|
||||
* Creates a circular (constant radius), closed (1st pos == last pos) geodesic linestring.
|
||||
* The number of vertices is calculated with: `vertices == steps + 1` (where 1st == last)
|
||||
*
|
||||
* @param center
|
||||
* @param radius
|
||||
* @return resulting linestring
|
||||
*/
|
||||
GeodesicGeometry.prototype.circle = function (center, radius) {
|
||||
var vertices = [];
|
||||
for (var i = 0; i < this.steps; i++) {
|
||||
var point = this.geodesic.direct(center, (360 / this.steps) * i, radius);
|
||||
vertices.push(new L.LatLng(point.lat, point.lng));
|
||||
}
|
||||
// append first vertice to the end to close the linestring
|
||||
vertices.push(new L.LatLng(vertices[0].lat, vertices[0].lng));
|
||||
return vertices;
|
||||
};
|
||||
/**
|
||||
* Handles splitting of circles at the antimeridian.
|
||||
* @param linestring a linestring that resembles the geodesic circle
|
||||
* @return a multilinestring that consist of one or two linestrings
|
||||
*/
|
||||
GeodesicGeometry.prototype.splitCircle = function (linestring) {
|
||||
var result = this.splitMultiLineString([linestring]);
|
||||
// If the circle was split, it results in exactly three linestrings where first and last
|
||||
// must be re-assembled because they belong to the same "side" of the split circle.
|
||||
if (result.length === 3) {
|
||||
result[2] = __spreadArray(__spreadArray([], result[2], true), result[0], true);
|
||||
result.shift();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/**
|
||||
* Calculates the distance between two positions on the earths surface
|
||||
* @param start 1st position
|
||||
* @param dest 2nd position
|
||||
* @return the distance in **meters**
|
||||
*/
|
||||
GeodesicGeometry.prototype.distance = function (start, dest) {
|
||||
return this.geodesic.inverse(new L.LatLng(start.lat, this.geodesic.wrap(start.lng, 180)), new L.LatLng(dest.lat, this.geodesic.wrap(dest.lng, 180))).distance;
|
||||
};
|
||||
GeodesicGeometry.prototype.multilineDistance = function (multilinestring) {
|
||||
var dist = [];
|
||||
for (var _i = 0, multilinestring_3 = multilinestring; _i < multilinestring_3.length; _i++) {
|
||||
var linestring = multilinestring_3[_i];
|
||||
var segmentDistance = 0;
|
||||
for (var j = 1; j < linestring.length; j++) {
|
||||
segmentDistance += this.distance(linestring[j - 1], linestring[j]);
|
||||
}
|
||||
dist.push(segmentDistance);
|
||||
}
|
||||
return dist;
|
||||
};
|
||||
GeodesicGeometry.prototype.updateStatistics = function (points, vertices) {
|
||||
var stats = { distanceArray: [], totalDistance: 0, points: 0, vertices: 0 };
|
||||
stats.distanceArray = this.multilineDistance(points);
|
||||
stats.totalDistance = stats.distanceArray.reduce(function (x, y) { return x + y; }, 0);
|
||||
stats.points = 0;
|
||||
for (var _i = 0, points_1 = points; _i < points_1.length; _i++) {
|
||||
var item = points_1[_i];
|
||||
stats.points += item.reduce(function (x) { return x + 1; }, 0);
|
||||
}
|
||||
stats.vertices = 0;
|
||||
for (var _a = 0, vertices_1 = vertices; _a < vertices_1.length; _a++) {
|
||||
var item = vertices_1[_a];
|
||||
stats.vertices += item.reduce(function (x) { return x + 1; }, 0);
|
||||
}
|
||||
return stats;
|
||||
};
|
||||
return GeodesicGeometry;
|
||||
}());
|
||||
|
||||
function instanceOfLatLngLiteral(object) {
|
||||
return ((typeof object === "object")
|
||||
&& (object !== null)
|
||||
&& ("lat" in object)
|
||||
&& ("lng" in object)
|
||||
&& (typeof object.lat === "number")
|
||||
&& (typeof object.lng === "number"));
|
||||
}
|
||||
function instanceOfLatLngTuple(object) {
|
||||
return ((object instanceof Array)
|
||||
&& (typeof object[0] === "number")
|
||||
&& (typeof object[1] === "number"));
|
||||
}
|
||||
function instanceOfLatLngExpression(object) {
|
||||
return object instanceof L.LatLng || instanceOfLatLngTuple(object) || instanceOfLatLngLiteral(object);
|
||||
}
|
||||
function latlngExpressiontoLatLng(input) {
|
||||
if (input instanceof L.LatLng) {
|
||||
return input;
|
||||
}
|
||||
else if (instanceOfLatLngTuple(input)) {
|
||||
return new L.LatLng(input[0], input[1], input.at(2)); // alt is optional
|
||||
}
|
||||
else if (instanceOfLatLngLiteral(input)) {
|
||||
return new L.LatLng(input.lat, input.lng, input.alt);
|
||||
}
|
||||
throw new Error("L.LatLngExpression expected. Unknown object found.");
|
||||
}
|
||||
function latlngExpressionArraytoLatLngArray(input) {
|
||||
var latlng = [];
|
||||
var iterateOver = instanceOfLatLngExpression(input[0]) ? [input] : input;
|
||||
var unknownObjectError = new Error("L.LatLngExpression[] | L.LatLngExpression[][] expected. Unknown object found.");
|
||||
if (!(iterateOver instanceof Array)) {
|
||||
throw unknownObjectError;
|
||||
}
|
||||
for (var _i = 0, _a = iterateOver; _i < _a.length; _i++) {
|
||||
var group = _a[_i];
|
||||
if (!(group instanceof Array)) {
|
||||
throw unknownObjectError;
|
||||
}
|
||||
var sub = [];
|
||||
for (var _b = 0, group_1 = group; _b < group_1.length; _b++) {
|
||||
var point = group_1[_b];
|
||||
if (!instanceOfLatLngExpression(point)) {
|
||||
throw unknownObjectError;
|
||||
}
|
||||
sub.push(latlngExpressiontoLatLng(point));
|
||||
}
|
||||
latlng.push(sub);
|
||||
}
|
||||
return latlng;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw geodesic lines based on L.Polyline
|
||||
*/
|
||||
var GeodesicLine = /** @class */ (function (_super) {
|
||||
__extends(GeodesicLine, _super);
|
||||
function GeodesicLine(latlngs, options) {
|
||||
var _this = _super.call(this, [], options) || this;
|
||||
/** these should be good for most use-cases */
|
||||
_this.defaultOptions = { wrap: true, steps: 3 };
|
||||
/** use this if you need some detailled info about the current geometry */
|
||||
_this.statistics = { distanceArray: [], totalDistance: 0, points: 0, vertices: 0 };
|
||||
/** stores all positions that are used to create the geodesic line */
|
||||
_this.points = [];
|
||||
L.Util.setOptions(_this, __assign(__assign({}, _this.defaultOptions), options));
|
||||
_this.geom = new GeodesicGeometry(_this.options);
|
||||
if (latlngs !== undefined) {
|
||||
_this.setLatLngs(latlngs);
|
||||
}
|
||||
return _this;
|
||||
}
|
||||
/** calculates the geodesics and update the polyline-object accordingly */
|
||||
GeodesicLine.prototype.updateGeometry = function () {
|
||||
var geodesic = [];
|
||||
geodesic = this.geom.multiLineString(this.points);
|
||||
this.statistics = this.geom.updateStatistics(this.points, geodesic);
|
||||
if (this.options.wrap) {
|
||||
var split = this.geom.splitMultiLineString(geodesic);
|
||||
_super.prototype.setLatLngs.call(this, split);
|
||||
}
|
||||
else {
|
||||
_super.prototype.setLatLngs.call(this, this.geom.wrapMultiLineString(geodesic));
|
||||
}
|
||||
};
|
||||
/**
|
||||
* overwrites the original function with additional functionality to create a geodesic line
|
||||
* @param latlngs an array (or 2d-array) of positions
|
||||
*/
|
||||
GeodesicLine.prototype.setLatLngs = function (latlngs) {
|
||||
this.points = latlngExpressionArraytoLatLngArray(latlngs);
|
||||
this.updateGeometry();
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* add a given point to the geodesic line object
|
||||
* @param latlng point to add. The point will always be added to the last linestring of a multiline
|
||||
* @param latlngs define a linestring to add the new point to. Read from points-property before (e.g. `line.addLatLng(Beijing, line.points[0]);`)
|
||||
*/
|
||||
GeodesicLine.prototype.addLatLng = function (latlng, latlngs) {
|
||||
var point = latlngExpressiontoLatLng(latlng);
|
||||
if (this.points.length === 0) {
|
||||
this.points.push([point]);
|
||||
}
|
||||
else if (latlngs === undefined) {
|
||||
this.points[this.points.length - 1].push(point);
|
||||
}
|
||||
else {
|
||||
latlngs.push(point);
|
||||
}
|
||||
this.updateGeometry();
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Creates geodesic lines from a given GeoJSON-Object.
|
||||
* @param input GeoJSON-Object
|
||||
*/
|
||||
GeodesicLine.prototype.fromGeoJson = function (input) {
|
||||
var latlngs = [];
|
||||
var features = [];
|
||||
if (input.type === "FeatureCollection") {
|
||||
features = input.features;
|
||||
}
|
||||
else if (input.type === "Feature") {
|
||||
features = [input];
|
||||
}
|
||||
else if (["MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon"].includes(input.type)) {
|
||||
features = [
|
||||
{
|
||||
type: "Feature",
|
||||
geometry: input,
|
||||
properties: {}
|
||||
}
|
||||
];
|
||||
}
|
||||
else {
|
||||
console.log("[Leaflet.Geodesic] fromGeoJson() - Type \"".concat(input.type, "\" not supported."));
|
||||
}
|
||||
features.forEach(function (feature) {
|
||||
switch (feature.geometry.type) {
|
||||
case "MultiPoint":
|
||||
case "LineString":
|
||||
latlngs = __spreadArray(__spreadArray([], latlngs, true), [L.GeoJSON.coordsToLatLngs(feature.geometry.coordinates, 0)], false);
|
||||
break;
|
||||
case "MultiLineString":
|
||||
case "Polygon":
|
||||
latlngs = __spreadArray(__spreadArray([], latlngs, true), L.GeoJSON.coordsToLatLngs(feature.geometry.coordinates, 1), true);
|
||||
break;
|
||||
case "MultiPolygon":
|
||||
feature.geometry.coordinates.forEach(function (item) {
|
||||
latlngs = __spreadArray(__spreadArray([], latlngs, true), L.GeoJSON.coordsToLatLngs(item, 1), true);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.log("[Leaflet.Geodesic] fromGeoJson() - Type \"".concat(feature.geometry.type, "\" not supported."));
|
||||
}
|
||||
});
|
||||
if (latlngs.length) {
|
||||
this.setLatLngs(latlngs);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Calculates the distance between two geo-positions
|
||||
* @param start 1st position
|
||||
* @param dest 2nd position
|
||||
* @return the distance in meters
|
||||
*/
|
||||
GeodesicLine.prototype.distance = function (start, dest) {
|
||||
return this.geom.distance(latlngExpressiontoLatLng(start), latlngExpressiontoLatLng(dest));
|
||||
};
|
||||
return GeodesicLine;
|
||||
}(L.Polyline));
|
||||
|
||||
/**
|
||||
* Can be used to create a geodesic circle based on L.Polyline
|
||||
*/
|
||||
var GeodesicCircleClass = /** @class */ (function (_super) {
|
||||
__extends(GeodesicCircleClass, _super);
|
||||
function GeodesicCircleClass(center, options) {
|
||||
var _a;
|
||||
var _this = _super.call(this, [], options) || this;
|
||||
_this.defaultOptions = { wrap: true, steps: 24, fill: true, noClip: true };
|
||||
_this.statistics = { distanceArray: [], totalDistance: 0, points: 0, vertices: 0 };
|
||||
L.Util.setOptions(_this, __assign(__assign({}, _this.defaultOptions), options));
|
||||
// merge/set options
|
||||
var extendedOptions = _this.options;
|
||||
_this.radius = (_a = extendedOptions.radius) !== null && _a !== void 0 ? _a : 1000 * 1000;
|
||||
_this.center = center === undefined ? new L.LatLng(0, 0) : latlngExpressiontoLatLng(center);
|
||||
_this.geom = new GeodesicGeometry(_this.options);
|
||||
// update the geometry
|
||||
_this.update();
|
||||
return _this;
|
||||
}
|
||||
/**
|
||||
* Updates the geometry and re-calculates some statistics
|
||||
*/
|
||||
GeodesicCircleClass.prototype.update = function () {
|
||||
var circle = this.geom.circle(this.center, this.radius);
|
||||
this.statistics = this.geom.updateStatistics([[this.center]], [circle]);
|
||||
// circumfence must be re-calculated from geodesic
|
||||
this.statistics.totalDistance = this.geom.multilineDistance([circle]).reduce(function (x, y) { return x + y; }, 0);
|
||||
if (this.options.wrap) {
|
||||
var split = this.geom.splitCircle(circle);
|
||||
_super.prototype.setLatLngs.call(this, split);
|
||||
}
|
||||
else {
|
||||
_super.prototype.setLatLngs.call(this, circle);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Calculate the distance between the current center and an arbitrary position.
|
||||
* @param latlng geo-position to calculate distance to
|
||||
* @return distance in meters
|
||||
*/
|
||||
GeodesicCircleClass.prototype.distanceTo = function (latlng) {
|
||||
var dest = latlngExpressiontoLatLng(latlng);
|
||||
return this.geom.distance(this.center, dest);
|
||||
};
|
||||
/**
|
||||
* Set a new center for the geodesic circle and update the geometry. Radius may also be set.
|
||||
* @param center the new center
|
||||
* @param radius the new radius
|
||||
*/
|
||||
GeodesicCircleClass.prototype.setLatLng = function (center, radius) {
|
||||
this.center = latlngExpressiontoLatLng(center);
|
||||
this.radius = radius !== null && radius !== void 0 ? radius : this.radius;
|
||||
this.update();
|
||||
};
|
||||
/**
|
||||
* Set a new radius for the geodesic circle and update the geometry. Center may also be set.
|
||||
* @param radius the new radius
|
||||
* @param center the new center
|
||||
*/
|
||||
GeodesicCircleClass.prototype.setRadius = function (radius, center) {
|
||||
this.radius = radius;
|
||||
this.center = center ? latlngExpressiontoLatLng(center) : this.center;
|
||||
this.update();
|
||||
};
|
||||
return GeodesicCircleClass;
|
||||
}(L.Polyline));
|
||||
|
||||
if (typeof window.L !== "undefined") {
|
||||
window.L.Geodesic = GeodesicLine;
|
||||
window.L.geodesic = function () {
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments[_i];
|
||||
}
|
||||
return new (GeodesicLine.bind.apply(GeodesicLine, __spreadArray([void 0], args, false)))();
|
||||
};
|
||||
window.L.GeodesicCircle = GeodesicCircleClass;
|
||||
window.L.geodesiccircle = function () {
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments[_i];
|
||||
}
|
||||
return new (GeodesicCircleClass.bind.apply(GeodesicCircleClass, __spreadArray([void 0], args, false)))();
|
||||
};
|
||||
}
|
||||
|
||||
export { GeodesicCircleClass, GeodesicLine };
|
||||
917
static/leaflet-geodesic/leaflet.geodesic.js
Normal file
917
static/leaflet-geodesic/leaflet.geodesic.js
Normal file
|
|
@ -0,0 +1,917 @@
|
|||
/*! leaflet.geodesic 2.7.1 - (c) Henry Thasler - https://github.com/henrythasler/Leaflet.Geodesic#readme */
|
||||
'use strict';
|
||||
|
||||
var L = require('leaflet');
|
||||
|
||||
function _interopNamespaceDefault(e) {
|
||||
var n = Object.create(null);
|
||||
if (e) {
|
||||
Object.keys(e).forEach(function (k) {
|
||||
if (k !== 'default') {
|
||||
var d = Object.getOwnPropertyDescriptor(e, k);
|
||||
Object.defineProperty(n, k, d.get ? d : {
|
||||
enumerable: true,
|
||||
get: function () { return e[k]; }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
n.default = e;
|
||||
return Object.freeze(n);
|
||||
}
|
||||
|
||||
var L__namespace = /*#__PURE__*/_interopNamespaceDefault(L);
|
||||
|
||||
/******************************************************************************
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
***************************************************************************** */
|
||||
/* global Reflect, Promise, SuppressedError, Symbol */
|
||||
|
||||
var extendStatics = function(d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
|
||||
function __extends(d, b) {
|
||||
if (typeof b !== "function" && b !== null)
|
||||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
}
|
||||
|
||||
var __assign = function() {
|
||||
__assign = Object.assign || function __assign(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
|
||||
function __spreadArray(to, from, pack) {
|
||||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
||||
if (ar || !(i in from)) {
|
||||
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
||||
ar[i] = from[i];
|
||||
}
|
||||
}
|
||||
return to.concat(ar || Array.prototype.slice.call(from));
|
||||
}
|
||||
|
||||
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
||||
var e = new Error(message);
|
||||
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
||||
};
|
||||
|
||||
var GeodesicCore = /** @class */ (function () {
|
||||
function GeodesicCore(options) {
|
||||
this.options = { wrap: true, steps: 3 };
|
||||
this.ellipsoid = {
|
||||
a: 6378137,
|
||||
b: 6356752.3142,
|
||||
f: 1 / 298.257223563
|
||||
}; // WGS-84
|
||||
this.options = __assign(__assign({}, this.options), options);
|
||||
}
|
||||
GeodesicCore.prototype.toRadians = function (degree) {
|
||||
return (degree * Math.PI) / 180;
|
||||
};
|
||||
GeodesicCore.prototype.toDegrees = function (radians) {
|
||||
return (radians * 180) / Math.PI;
|
||||
};
|
||||
/**
|
||||
* implements scientific modulus
|
||||
* source: http://www.codeavenger.com/2017/05/19/JavaScript-Modulo-operation-and-the-Caesar-Cipher.html
|
||||
* @param n
|
||||
* @param p
|
||||
* @return
|
||||
*/
|
||||
GeodesicCore.prototype.mod = function (n, p) {
|
||||
var r = n % p;
|
||||
return r < 0 ? r + p : r;
|
||||
};
|
||||
/**
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/dms.js
|
||||
* @param degrees arbitrary value
|
||||
* @return degrees between 0..360
|
||||
*/
|
||||
GeodesicCore.prototype.wrap360 = function (degrees) {
|
||||
if (0 <= degrees && degrees < 360) {
|
||||
return degrees; // avoid rounding due to arithmetic ops if within range
|
||||
}
|
||||
else {
|
||||
return this.mod(degrees, 360);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* general wrap function with arbitrary max value
|
||||
* @param degrees arbitrary value
|
||||
* @param max
|
||||
* @return degrees between `-max`..`+max`
|
||||
*/
|
||||
GeodesicCore.prototype.wrap = function (degrees, max) {
|
||||
if (max === void 0) { max = 360; }
|
||||
if (-max <= degrees && degrees <= max) {
|
||||
return degrees;
|
||||
}
|
||||
else {
|
||||
return this.mod(degrees + max, 2 * max) - max;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Vincenty direct calculation.
|
||||
* based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/latlon-ellipsoidal-vincenty.js
|
||||
*
|
||||
* @param start starting point
|
||||
* @param bearing initial bearing (in degrees)
|
||||
* @param distance distance from starting point to calculate along given bearing in meters.
|
||||
* @param maxInterations How many iterations can be made to reach the allowed deviation (`ε`), before an error will be thrown.
|
||||
* @return Final point (destination point) and bearing (in degrees)
|
||||
*/
|
||||
GeodesicCore.prototype.direct = function (start, bearing, distance, maxInterations) {
|
||||
if (maxInterations === void 0) { maxInterations = 100; }
|
||||
var φ1 = this.toRadians(start.lat);
|
||||
var λ1 = this.toRadians(start.lng);
|
||||
var α1 = this.toRadians(bearing);
|
||||
var s = distance;
|
||||
var ε = Number.EPSILON * 1000;
|
||||
var _a = this.ellipsoid, a = _a.a, b = _a.b, f = _a.f;
|
||||
var sinα1 = Math.sin(α1);
|
||||
var cosα1 = Math.cos(α1);
|
||||
var tanU1 = (1 - f) * Math.tan(φ1), cosU1 = 1 / Math.sqrt(1 + tanU1 * tanU1), sinU1 = tanU1 * cosU1;
|
||||
var σ1 = Math.atan2(tanU1, cosα1); // σ1 = angular distance on the sphere from the equator to P1
|
||||
var sinα = cosU1 * sinα1; // α = azimuth of the geodesic at the equator
|
||||
var cosSqα = 1 - sinα * sinα;
|
||||
var uSq = (cosSqα * (a * a - b * b)) / (b * b);
|
||||
var A = 1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
|
||||
var B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
|
||||
var σ = s / (b * A), sinσ = null, cosσ = null, Δσ = null; // σ = angular distance P₁ P₂ on the sphere
|
||||
var cos2σₘ = null; // σₘ = angular distance on the sphere from the equator to the midpoint of the line
|
||||
var σʹ = null, iterations = 0;
|
||||
do {
|
||||
cos2σₘ = Math.cos(2 * σ1 + σ);
|
||||
sinσ = Math.sin(σ);
|
||||
cosσ = Math.cos(σ);
|
||||
Δσ =
|
||||
B *
|
||||
sinσ *
|
||||
(cos2σₘ +
|
||||
(B / 4) *
|
||||
(cosσ * (-1 + 2 * cos2σₘ * cos2σₘ) -
|
||||
(B / 6) * cos2σₘ * (-3 + 4 * sinσ * sinσ) * (-3 + 4 * cos2σₘ * cos2σₘ)));
|
||||
σʹ = σ;
|
||||
σ = s / (b * A) + Δσ;
|
||||
} while (Math.abs(σ - σʹ) > ε && ++iterations < maxInterations);
|
||||
if (iterations >= maxInterations) {
|
||||
throw new EvalError("Direct vincenty formula failed to converge after ".concat(maxInterations, " iterations \n (start=").concat(start.lat, "/").concat(start.lng, "; bearing=").concat(bearing, "; distance=").concat(distance, ")")); // not possible?
|
||||
}
|
||||
var x = sinU1 * sinσ - cosU1 * cosσ * cosα1;
|
||||
var φ2 = Math.atan2(sinU1 * cosσ + cosU1 * sinσ * cosα1, (1 - f) * Math.sqrt(sinα * sinα + x * x));
|
||||
var λ = Math.atan2(sinσ * sinα1, cosU1 * cosσ - sinU1 * sinσ * cosα1);
|
||||
var C = (f / 16) * cosSqα * (4 + f * (4 - 3 * cosSqα));
|
||||
var dL = λ - (1 - C) * f * sinα * (σ + C * sinσ * (cos2σₘ + C * cosσ * (-1 + 2 * cos2σₘ * cos2σₘ)));
|
||||
var λ2 = λ1 + dL;
|
||||
var α2 = Math.atan2(sinα, -x);
|
||||
return {
|
||||
lat: this.toDegrees(φ2),
|
||||
lng: this.toDegrees(λ2),
|
||||
bearing: this.wrap360(this.toDegrees(α2))
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Vincenty inverse calculation.
|
||||
* based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/latlon-ellipsoidal-vincenty.js
|
||||
*
|
||||
* @param start Latitude/longitude of starting point.
|
||||
* @param dest Latitude/longitude of destination point.
|
||||
* @return Object including distance, initialBearing, finalBearing.
|
||||
*/
|
||||
GeodesicCore.prototype.inverse = function (start, dest, maxInterations, mitigateConvergenceError) {
|
||||
if (maxInterations === void 0) { maxInterations = 100; }
|
||||
if (mitigateConvergenceError === void 0) { mitigateConvergenceError = true; }
|
||||
var p1 = start, p2 = dest;
|
||||
var φ1 = this.toRadians(p1.lat), λ1 = this.toRadians(p1.lng);
|
||||
var φ2 = this.toRadians(p2.lat), λ2 = this.toRadians(p2.lng);
|
||||
var π = Math.PI;
|
||||
var ε = Number.EPSILON;
|
||||
// allow alternative ellipsoid to be specified
|
||||
var _a = this.ellipsoid, a = _a.a, b = _a.b, f = _a.f;
|
||||
var dL = λ2 - λ1; // L = difference in longitude, U = reduced latitude, defined by tan U = (1-f)·tanφ.
|
||||
var tanU1 = (1 - f) * Math.tan(φ1), cosU1 = 1 / Math.sqrt(1 + tanU1 * tanU1), sinU1 = tanU1 * cosU1;
|
||||
var tanU2 = (1 - f) * Math.tan(φ2), cosU2 = 1 / Math.sqrt(1 + tanU2 * tanU2), sinU2 = tanU2 * cosU2;
|
||||
var antipodal = Math.abs(dL) > π / 2 || Math.abs(φ2 - φ1) > π / 2;
|
||||
var λ = dL, sinλ = null, cosλ = null; // λ = difference in longitude on an auxiliary sphere
|
||||
var σ = antipodal ? π : 0, sinσ = 0, cosσ = antipodal ? -1 : 1, sinSqσ = null; // σ = angular distance P₁ P₂ on the sphere
|
||||
var cos2σₘ = 1; // σₘ = angular distance on the sphere from the equator to the midpoint of the line
|
||||
var sinα = null, cosSqα = 1; // α = azimuth of the geodesic at the equator
|
||||
var C = null;
|
||||
var λʹ = null, iterations = 0;
|
||||
do {
|
||||
sinλ = Math.sin(λ);
|
||||
cosλ = Math.cos(λ);
|
||||
sinSqσ =
|
||||
cosU2 * sinλ * (cosU2 * sinλ) +
|
||||
(cosU1 * sinU2 - sinU1 * cosU2 * cosλ) * (cosU1 * sinU2 - sinU1 * cosU2 * cosλ);
|
||||
if (Math.abs(sinSqσ) < ε) {
|
||||
break; // co-incident/antipodal points (falls back on λ/σ = L)
|
||||
}
|
||||
sinσ = Math.sqrt(sinSqσ);
|
||||
cosσ = sinU1 * sinU2 + cosU1 * cosU2 * cosλ;
|
||||
σ = Math.atan2(sinσ, cosσ);
|
||||
sinα = (cosU1 * cosU2 * sinλ) / sinσ;
|
||||
cosSqα = 1 - sinα * sinα;
|
||||
cos2σₘ = cosSqα !== 0 ? cosσ - (2 * sinU1 * sinU2) / cosSqα : 0; // on equatorial line cos²α = 0 (§6)
|
||||
C = (f / 16) * cosSqα * (4 + f * (4 - 3 * cosSqα));
|
||||
λʹ = λ;
|
||||
λ = dL + (1 - C) * f * sinα * (σ + C * sinσ * (cos2σₘ + C * cosσ * (-1 + 2 * cos2σₘ * cos2σₘ)));
|
||||
var iterationCheck = antipodal ? Math.abs(λ) - π : Math.abs(λ);
|
||||
if (iterationCheck > π) {
|
||||
throw new EvalError("λ > π");
|
||||
}
|
||||
} while (Math.abs(λ - λʹ) > 1e-12 && ++iterations < maxInterations);
|
||||
if (iterations >= maxInterations) {
|
||||
if (mitigateConvergenceError) {
|
||||
return this.inverse(start, new L__namespace.LatLng(dest.lat, dest.lng - 0.01), maxInterations, mitigateConvergenceError);
|
||||
}
|
||||
else {
|
||||
throw new EvalError("Inverse vincenty formula failed to converge after ".concat(maxInterations, " iterations \n (start=").concat(start.lat, "/").concat(start.lng, "; dest=").concat(dest.lat, "/").concat(dest.lng, ")"));
|
||||
}
|
||||
}
|
||||
var uSq = (cosSqα * (a * a - b * b)) / (b * b);
|
||||
var A = 1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
|
||||
var B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
|
||||
var Δσ = B *
|
||||
sinσ *
|
||||
(cos2σₘ +
|
||||
(B / 4) *
|
||||
(cosσ * (-1 + 2 * cos2σₘ * cos2σₘ) -
|
||||
(B / 6) * cos2σₘ * (-3 + 4 * sinσ * sinσ) * (-3 + 4 * cos2σₘ * cos2σₘ)));
|
||||
var s = b * A * (σ - Δσ); // s = length of the geodesic
|
||||
// note special handling of exactly antipodal points where sin²σ = 0 (due to discontinuity
|
||||
// atan2(0, 0) = 0 but atan2(this.ε, 0) = π/2 / 90°) - in which case bearing is always meridional,
|
||||
// due north (or due south!)
|
||||
// α = azimuths of the geodesic; α2 the direction P₁ P₂ produced
|
||||
var α1 = Math.abs(sinSqσ) < ε ? 0 : Math.atan2(cosU2 * sinλ, cosU1 * sinU2 - sinU1 * cosU2 * cosλ);
|
||||
var α2 = Math.abs(sinSqσ) < ε ? π : Math.atan2(cosU1 * sinλ, -sinU1 * cosU2 + cosU1 * sinU2 * cosλ);
|
||||
return {
|
||||
distance: s,
|
||||
initialBearing: Math.abs(s) < ε ? NaN : this.wrap360(this.toDegrees(α1)),
|
||||
finalBearing: Math.abs(s) < ε ? NaN : this.wrap360(this.toDegrees(α2))
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Returns the point of intersection of two paths defined by position and bearing.
|
||||
* This calculation uses a spherical model of the earth. This will lead to small errors compared to an ellipsiod model.
|
||||
* based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js
|
||||
*
|
||||
* @param firstPos 1st path: position and bearing
|
||||
* @param firstBearing
|
||||
* @param secondPos 2nd path: position and bearing
|
||||
* @param secondBearing
|
||||
*/
|
||||
GeodesicCore.prototype.intersection = function (firstPos, firstBearing, secondPos, secondBearing) {
|
||||
var φ1 = this.toRadians(firstPos.lat);
|
||||
var λ1 = this.toRadians(firstPos.lng);
|
||||
var φ2 = this.toRadians(secondPos.lat);
|
||||
var λ2 = this.toRadians(secondPos.lng);
|
||||
var θ13 = this.toRadians(firstBearing);
|
||||
var θ23 = this.toRadians(secondBearing);
|
||||
var Δφ = φ2 - φ1, Δλ = λ2 - λ1;
|
||||
var π = Math.PI;
|
||||
var ε = Number.EPSILON;
|
||||
// angular distance p1-p2
|
||||
var δ12 = 2 *
|
||||
Math.asin(Math.sqrt(Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
|
||||
Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2)));
|
||||
if (Math.abs(δ12) < ε) {
|
||||
return firstPos; // coincident points
|
||||
}
|
||||
// initial/final bearings between points
|
||||
var cosθa = (Math.sin(φ2) - Math.sin(φ1) * Math.cos(δ12)) / (Math.sin(δ12) * Math.cos(φ1));
|
||||
var cosθb = (Math.sin(φ1) - Math.sin(φ2) * Math.cos(δ12)) / (Math.sin(δ12) * Math.cos(φ2));
|
||||
var θa = Math.acos(Math.min(Math.max(cosθa, -1), 1)); // protect against rounding errors
|
||||
var θb = Math.acos(Math.min(Math.max(cosθb, -1), 1)); // protect against rounding errors
|
||||
var θ12 = Math.sin(λ2 - λ1) > 0 ? θa : 2 * π - θa;
|
||||
var θ21 = Math.sin(λ2 - λ1) > 0 ? 2 * π - θb : θb;
|
||||
var α1 = θ13 - θ12; // angle 2-1-3
|
||||
var α2 = θ21 - θ23; // angle 1-2-3
|
||||
if (Math.sin(α1) === 0 && Math.sin(α2) === 0) {
|
||||
return null; // infinite intersections
|
||||
}
|
||||
if (Math.sin(α1) * Math.sin(α2) < 0) {
|
||||
return null; // ambiguous intersection (antipodal?)
|
||||
}
|
||||
var cosα3 = -Math.cos(α1) * Math.cos(α2) + Math.sin(α1) * Math.sin(α2) * Math.cos(δ12);
|
||||
var δ13 = Math.atan2(Math.sin(δ12) * Math.sin(α1) * Math.sin(α2), Math.cos(α2) + Math.cos(α1) * cosα3);
|
||||
var φ3 = Math.asin(Math.min(Math.max(Math.sin(φ1) * Math.cos(δ13) + Math.cos(φ1) * Math.sin(δ13) * Math.cos(θ13), -1), 1));
|
||||
var Δλ13 = Math.atan2(Math.sin(θ13) * Math.sin(δ13) * Math.cos(φ1), Math.cos(δ13) - Math.sin(φ1) * Math.sin(φ3));
|
||||
var λ3 = λ1 + Δλ13;
|
||||
return new L__namespace.LatLng(this.toDegrees(φ3), this.toDegrees(λ3));
|
||||
};
|
||||
GeodesicCore.prototype.midpoint = function (start, dest) {
|
||||
// φm = atan2( sinφ1 + sinφ2, √( (cosφ1 + cosφ2⋅cosΔλ)² + cos²φ2⋅sin²Δλ ) )
|
||||
// λm = λ1 + atan2(cosφ2⋅sinΔλ, cosφ1 + cosφ2⋅cosΔλ)
|
||||
// midpoint is sum of vectors to two points: mathforum.org/library/drmath/view/51822.html
|
||||
var φ1 = this.toRadians(start.lat);
|
||||
var λ1 = this.toRadians(start.lng);
|
||||
var φ2 = this.toRadians(dest.lat);
|
||||
var Δλ = this.toRadians(dest.lng - start.lng);
|
||||
// get cartesian coordinates for the two points
|
||||
var A = { x: Math.cos(φ1), y: 0, z: Math.sin(φ1) }; // place point A on prime meridian y=0
|
||||
var B = { x: Math.cos(φ2) * Math.cos(Δλ), y: Math.cos(φ2) * Math.sin(Δλ), z: Math.sin(φ2) };
|
||||
// vector to midpoint is sum of vectors to two points (no need to normalise)
|
||||
var C = { x: A.x + B.x, y: A.y + B.y, z: A.z + B.z };
|
||||
var φm = Math.atan2(C.z, Math.sqrt(C.x * C.x + C.y * C.y));
|
||||
var λm = λ1 + Math.atan2(C.y, C.x);
|
||||
return new L__namespace.LatLng(this.toDegrees(φm), this.toDegrees(λm));
|
||||
};
|
||||
return GeodesicCore;
|
||||
}());
|
||||
|
||||
var GeodesicGeometry = /** @class */ (function () {
|
||||
function GeodesicGeometry(options) {
|
||||
var _a;
|
||||
this.geodesic = new GeodesicCore();
|
||||
this.steps = (_a = options === null || options === void 0 ? void 0 : options.steps) !== null && _a !== void 0 ? _a : 3;
|
||||
}
|
||||
/**
|
||||
* A geodesic line between `start` and `dest` is created with this recursive function.
|
||||
* It calculates the geodesic midpoint between `start` and `dest` and uses this midpoint to call itself again (twice!).
|
||||
* The results are then merged into one continuous linestring.
|
||||
*
|
||||
* The number of resulting vertices (incl. `start` and `dest`) depends on the initial value for `iterations`
|
||||
* and can be calculated with: vertices == 1 + 2 ** (initialIterations + 1)
|
||||
*
|
||||
* As this is an exponential function, be extra careful to limit the initial value for `iterations` (8 results in 513 vertices).
|
||||
*
|
||||
* @param start start position
|
||||
* @param dest destination
|
||||
* @param iterations
|
||||
* @return resulting linestring
|
||||
*/
|
||||
GeodesicGeometry.prototype.recursiveMidpoint = function (start, dest, iterations) {
|
||||
var geom = [start, dest];
|
||||
var midpoint = this.geodesic.midpoint(start, dest);
|
||||
if (iterations > 0) {
|
||||
geom.splice.apply(geom, __spreadArray([0, 1], this.recursiveMidpoint(start, midpoint, iterations - 1), false));
|
||||
geom.splice.apply(geom, __spreadArray([geom.length - 2, 2], this.recursiveMidpoint(midpoint, dest, iterations - 1), false));
|
||||
}
|
||||
else {
|
||||
geom.splice(1, 0, midpoint);
|
||||
}
|
||||
return geom;
|
||||
};
|
||||
/**
|
||||
* This is the wrapper-function to generate a geodesic line. It's just for future backwards-compatibility
|
||||
* if there is another algorithm used to create the actual line.
|
||||
*
|
||||
* The `steps`-property is used to define the number of resulting vertices of the linestring: vertices == 1 + 2 ** (steps + 1)
|
||||
* The value for `steps` is currently limited to 8 (513 vertices) for performance reasons until another algorithm is found.
|
||||
*
|
||||
* @param start start position
|
||||
* @param dest destination
|
||||
* @return resulting linestring
|
||||
*/
|
||||
GeodesicGeometry.prototype.line = function (start, dest) {
|
||||
return this.recursiveMidpoint(start, dest, Math.min(8, this.steps));
|
||||
};
|
||||
GeodesicGeometry.prototype.multiLineString = function (latlngs) {
|
||||
var multiLineString = [];
|
||||
for (var _i = 0, latlngs_1 = latlngs; _i < latlngs_1.length; _i++) {
|
||||
var linestring = latlngs_1[_i];
|
||||
var segment = [];
|
||||
for (var j = 1; j < linestring.length; j++) {
|
||||
segment.splice.apply(segment, __spreadArray([segment.length - 1, 1], this.line(linestring[j - 1], linestring[j]), false));
|
||||
}
|
||||
multiLineString.push(segment);
|
||||
}
|
||||
return multiLineString;
|
||||
};
|
||||
GeodesicGeometry.prototype.lineString = function (latlngs) {
|
||||
return this.multiLineString([latlngs])[0];
|
||||
};
|
||||
/**
|
||||
*
|
||||
* Is much (10x) faster than the previous implementation:
|
||||
*
|
||||
* ```
|
||||
* Benchmark (no split): splitLine x 459,044 ops/sec ±0.53% (95 runs sampled)
|
||||
* Benchmark (split): splitLine x 42,999 ops/sec ±0.51% (97 runs sampled)
|
||||
* ```
|
||||
*
|
||||
* @param startPosition
|
||||
* @param destPosition
|
||||
*/
|
||||
GeodesicGeometry.prototype.splitLine = function (startPosition, destPosition) {
|
||||
var antimeridianWest = {
|
||||
point: new L__namespace.LatLng(89.9, -180.0000001),
|
||||
bearing: 180
|
||||
};
|
||||
var antimeridianEast = {
|
||||
point: new L__namespace.LatLng(89.9, 180.0000001),
|
||||
bearing: 180
|
||||
};
|
||||
// make a copy to work with
|
||||
var start = new L__namespace.LatLng(startPosition.lat, startPosition.lng, startPosition.alt);
|
||||
var dest = new L__namespace.LatLng(destPosition.lat, destPosition.lng, destPosition.alt);
|
||||
start.lng = this.geodesic.wrap(start.lng, 360);
|
||||
dest.lng = this.geodesic.wrap(dest.lng, 360);
|
||||
if (dest.lng - start.lng > 180) {
|
||||
dest.lng = dest.lng - 360;
|
||||
}
|
||||
else if (dest.lng - start.lng < -180) {
|
||||
dest.lng = dest.lng + 360;
|
||||
}
|
||||
var result = [
|
||||
[
|
||||
new L__namespace.LatLng(start.lat, this.geodesic.wrap(start.lng, 180), start.alt),
|
||||
new L__namespace.LatLng(dest.lat, this.geodesic.wrap(dest.lng, 180), dest.alt)
|
||||
]
|
||||
];
|
||||
// crossing antimeridian from "this" side?
|
||||
if (start.lng >= -180 && start.lng <= 180) {
|
||||
// crossing the "western" antimeridian
|
||||
if (dest.lng < -180) {
|
||||
var bearing = this.geodesic.inverse(start, dest).initialBearing;
|
||||
var intersection = this.geodesic.intersection(start, bearing, antimeridianWest.point, antimeridianWest.bearing);
|
||||
if (intersection) {
|
||||
result = [
|
||||
[start, intersection],
|
||||
[
|
||||
new L__namespace.LatLng(intersection.lat, intersection.lng + 360),
|
||||
new L__namespace.LatLng(dest.lat, dest.lng + 360, dest.alt)
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
// crossing the "eastern" antimeridian
|
||||
else if (dest.lng > 180) {
|
||||
var bearing = this.geodesic.inverse(start, dest).initialBearing;
|
||||
var intersection = this.geodesic.intersection(start, bearing, antimeridianEast.point, antimeridianEast.bearing);
|
||||
if (intersection) {
|
||||
result = [
|
||||
[start, intersection],
|
||||
[
|
||||
new L__namespace.LatLng(intersection.lat, intersection.lng - 360),
|
||||
new L__namespace.LatLng(dest.lat, dest.lng - 360, dest.alt)
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
// coming back over the antimeridian from the "other" side?
|
||||
else if (dest.lng >= -180 && dest.lng <= 180) {
|
||||
// crossing the "western" antimeridian
|
||||
if (start.lng < -180) {
|
||||
var bearing = this.geodesic.inverse(start, dest).initialBearing;
|
||||
var intersection = this.geodesic.intersection(start, bearing, antimeridianWest.point, antimeridianWest.bearing);
|
||||
if (intersection) {
|
||||
result = [
|
||||
[
|
||||
new L__namespace.LatLng(start.lat, start.lng + 360, start.alt),
|
||||
new L__namespace.LatLng(intersection.lat, intersection.lng + 360)
|
||||
],
|
||||
[intersection, dest]
|
||||
];
|
||||
}
|
||||
}
|
||||
// crossing the "eastern" antimeridian
|
||||
else if (start.lng > 180) {
|
||||
var bearing = this.geodesic.inverse(start, dest).initialBearing;
|
||||
var intersection = this.geodesic.intersection(start, bearing, antimeridianWest.point, antimeridianWest.bearing);
|
||||
if (intersection) {
|
||||
result = [
|
||||
[
|
||||
new L__namespace.LatLng(start.lat, start.lng - 360, start.alt),
|
||||
new L__namespace.LatLng(intersection.lat, intersection.lng - 360)
|
||||
],
|
||||
[intersection, dest]
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/**
|
||||
* Linestrings of a given multilinestring that cross the antimeridian will be split in two separate linestrings.
|
||||
* This function is used to wrap lines around when they cross the antimeridian
|
||||
* It iterates over all linestrings and reconstructs the step-by-step if no split is needed.
|
||||
* In case the line was split, the linestring ends at the antimeridian and a new linestring is created for the
|
||||
* remaining points of the original linestring.
|
||||
*
|
||||
* @param multilinestring
|
||||
* @return another multilinestring where segments crossing the antimeridian are split
|
||||
*/
|
||||
GeodesicGeometry.prototype.splitMultiLineString = function (multilinestring) {
|
||||
var result = [];
|
||||
for (var _i = 0, multilinestring_1 = multilinestring; _i < multilinestring_1.length; _i++) {
|
||||
var linestring = multilinestring_1[_i];
|
||||
if (linestring.length === 1) {
|
||||
result.push(linestring); // just a single point in linestring, no need to split
|
||||
continue;
|
||||
}
|
||||
var segment = [];
|
||||
for (var j = 1; j < linestring.length; j++) {
|
||||
var split = this.splitLine(linestring[j - 1], linestring[j]);
|
||||
segment.pop();
|
||||
segment = segment.concat(split[0]);
|
||||
if (split.length > 1) {
|
||||
result.push(segment); // the line was split, so we end the linestring right here
|
||||
segment = split[1]; // begin the new linestring with the second part of the split line
|
||||
}
|
||||
}
|
||||
result.push(segment);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/**
|
||||
* Linestrings of a given multilinestring will be wrapped (+- 360°) to show a continuous line w/o any weird discontinuities
|
||||
* when `wrap` is set to `false` in the geodesic class
|
||||
* @param multilinestring
|
||||
* @returns another multilinestring where the points of each linestring are wrapped accordingly
|
||||
*/
|
||||
GeodesicGeometry.prototype.wrapMultiLineString = function (multilinestring) {
|
||||
var result = [];
|
||||
for (var _i = 0, multilinestring_2 = multilinestring; _i < multilinestring_2.length; _i++) {
|
||||
var linestring = multilinestring_2[_i];
|
||||
var resultLine = [];
|
||||
var previous = null;
|
||||
// iterate over every point and check if it needs to be wrapped
|
||||
for (var _a = 0, linestring_1 = linestring; _a < linestring_1.length; _a++) {
|
||||
var point = linestring_1[_a];
|
||||
if (previous === null) {
|
||||
// the first point is the anchor of the linestring from which the line will always start (w/o any wrapping applied)
|
||||
resultLine.push(new L__namespace.LatLng(point.lat, point.lng));
|
||||
previous = new L__namespace.LatLng(point.lat, point.lng);
|
||||
}
|
||||
else {
|
||||
// I prefer clearly defined branches over a continue-operation.
|
||||
// if the difference between the current and *previous* point is greater than 360°, the current point needs to be shifted
|
||||
// to be on the same 'sphere' as the previous one.
|
||||
var offset = Math.round((point.lng - previous.lng) / 360);
|
||||
// shift the point accordingly and add to the result
|
||||
resultLine.push(new L__namespace.LatLng(point.lat, point.lng - offset * 360));
|
||||
// use the wrapped point as the anchor for the next one
|
||||
previous = new L__namespace.LatLng(point.lat, point.lng - offset * 360); // Need a new object here, to avoid changing the input data
|
||||
}
|
||||
}
|
||||
result.push(resultLine);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/**
|
||||
* Creates a circular (constant radius), closed (1st pos == last pos) geodesic linestring.
|
||||
* The number of vertices is calculated with: `vertices == steps + 1` (where 1st == last)
|
||||
*
|
||||
* @param center
|
||||
* @param radius
|
||||
* @return resulting linestring
|
||||
*/
|
||||
GeodesicGeometry.prototype.circle = function (center, radius) {
|
||||
var vertices = [];
|
||||
for (var i = 0; i < this.steps; i++) {
|
||||
var point = this.geodesic.direct(center, (360 / this.steps) * i, radius);
|
||||
vertices.push(new L__namespace.LatLng(point.lat, point.lng));
|
||||
}
|
||||
// append first vertice to the end to close the linestring
|
||||
vertices.push(new L__namespace.LatLng(vertices[0].lat, vertices[0].lng));
|
||||
return vertices;
|
||||
};
|
||||
/**
|
||||
* Handles splitting of circles at the antimeridian.
|
||||
* @param linestring a linestring that resembles the geodesic circle
|
||||
* @return a multilinestring that consist of one or two linestrings
|
||||
*/
|
||||
GeodesicGeometry.prototype.splitCircle = function (linestring) {
|
||||
var result = this.splitMultiLineString([linestring]);
|
||||
// If the circle was split, it results in exactly three linestrings where first and last
|
||||
// must be re-assembled because they belong to the same "side" of the split circle.
|
||||
if (result.length === 3) {
|
||||
result[2] = __spreadArray(__spreadArray([], result[2], true), result[0], true);
|
||||
result.shift();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/**
|
||||
* Calculates the distance between two positions on the earths surface
|
||||
* @param start 1st position
|
||||
* @param dest 2nd position
|
||||
* @return the distance in **meters**
|
||||
*/
|
||||
GeodesicGeometry.prototype.distance = function (start, dest) {
|
||||
return this.geodesic.inverse(new L__namespace.LatLng(start.lat, this.geodesic.wrap(start.lng, 180)), new L__namespace.LatLng(dest.lat, this.geodesic.wrap(dest.lng, 180))).distance;
|
||||
};
|
||||
GeodesicGeometry.prototype.multilineDistance = function (multilinestring) {
|
||||
var dist = [];
|
||||
for (var _i = 0, multilinestring_3 = multilinestring; _i < multilinestring_3.length; _i++) {
|
||||
var linestring = multilinestring_3[_i];
|
||||
var segmentDistance = 0;
|
||||
for (var j = 1; j < linestring.length; j++) {
|
||||
segmentDistance += this.distance(linestring[j - 1], linestring[j]);
|
||||
}
|
||||
dist.push(segmentDistance);
|
||||
}
|
||||
return dist;
|
||||
};
|
||||
GeodesicGeometry.prototype.updateStatistics = function (points, vertices) {
|
||||
var stats = { distanceArray: [], totalDistance: 0, points: 0, vertices: 0 };
|
||||
stats.distanceArray = this.multilineDistance(points);
|
||||
stats.totalDistance = stats.distanceArray.reduce(function (x, y) { return x + y; }, 0);
|
||||
stats.points = 0;
|
||||
for (var _i = 0, points_1 = points; _i < points_1.length; _i++) {
|
||||
var item = points_1[_i];
|
||||
stats.points += item.reduce(function (x) { return x + 1; }, 0);
|
||||
}
|
||||
stats.vertices = 0;
|
||||
for (var _a = 0, vertices_1 = vertices; _a < vertices_1.length; _a++) {
|
||||
var item = vertices_1[_a];
|
||||
stats.vertices += item.reduce(function (x) { return x + 1; }, 0);
|
||||
}
|
||||
return stats;
|
||||
};
|
||||
return GeodesicGeometry;
|
||||
}());
|
||||
|
||||
function instanceOfLatLngLiteral(object) {
|
||||
return ((typeof object === "object")
|
||||
&& (object !== null)
|
||||
&& ("lat" in object)
|
||||
&& ("lng" in object)
|
||||
&& (typeof object.lat === "number")
|
||||
&& (typeof object.lng === "number"));
|
||||
}
|
||||
function instanceOfLatLngTuple(object) {
|
||||
return ((object instanceof Array)
|
||||
&& (typeof object[0] === "number")
|
||||
&& (typeof object[1] === "number"));
|
||||
}
|
||||
function instanceOfLatLngExpression(object) {
|
||||
return object instanceof L__namespace.LatLng || instanceOfLatLngTuple(object) || instanceOfLatLngLiteral(object);
|
||||
}
|
||||
function latlngExpressiontoLatLng(input) {
|
||||
if (input instanceof L__namespace.LatLng) {
|
||||
return input;
|
||||
}
|
||||
else if (instanceOfLatLngTuple(input)) {
|
||||
return new L__namespace.LatLng(input[0], input[1], input.at(2)); // alt is optional
|
||||
}
|
||||
else if (instanceOfLatLngLiteral(input)) {
|
||||
return new L__namespace.LatLng(input.lat, input.lng, input.alt);
|
||||
}
|
||||
throw new Error("L.LatLngExpression expected. Unknown object found.");
|
||||
}
|
||||
function latlngExpressionArraytoLatLngArray(input) {
|
||||
var latlng = [];
|
||||
var iterateOver = instanceOfLatLngExpression(input[0]) ? [input] : input;
|
||||
var unknownObjectError = new Error("L.LatLngExpression[] | L.LatLngExpression[][] expected. Unknown object found.");
|
||||
if (!(iterateOver instanceof Array)) {
|
||||
throw unknownObjectError;
|
||||
}
|
||||
for (var _i = 0, _a = iterateOver; _i < _a.length; _i++) {
|
||||
var group = _a[_i];
|
||||
if (!(group instanceof Array)) {
|
||||
throw unknownObjectError;
|
||||
}
|
||||
var sub = [];
|
||||
for (var _b = 0, group_1 = group; _b < group_1.length; _b++) {
|
||||
var point = group_1[_b];
|
||||
if (!instanceOfLatLngExpression(point)) {
|
||||
throw unknownObjectError;
|
||||
}
|
||||
sub.push(latlngExpressiontoLatLng(point));
|
||||
}
|
||||
latlng.push(sub);
|
||||
}
|
||||
return latlng;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw geodesic lines based on L.Polyline
|
||||
*/
|
||||
var GeodesicLine = /** @class */ (function (_super) {
|
||||
__extends(GeodesicLine, _super);
|
||||
function GeodesicLine(latlngs, options) {
|
||||
var _this = _super.call(this, [], options) || this;
|
||||
/** these should be good for most use-cases */
|
||||
_this.defaultOptions = { wrap: true, steps: 3 };
|
||||
/** use this if you need some detailled info about the current geometry */
|
||||
_this.statistics = { distanceArray: [], totalDistance: 0, points: 0, vertices: 0 };
|
||||
/** stores all positions that are used to create the geodesic line */
|
||||
_this.points = [];
|
||||
L__namespace.Util.setOptions(_this, __assign(__assign({}, _this.defaultOptions), options));
|
||||
_this.geom = new GeodesicGeometry(_this.options);
|
||||
if (latlngs !== undefined) {
|
||||
_this.setLatLngs(latlngs);
|
||||
}
|
||||
return _this;
|
||||
}
|
||||
/** calculates the geodesics and update the polyline-object accordingly */
|
||||
GeodesicLine.prototype.updateGeometry = function () {
|
||||
var geodesic = [];
|
||||
geodesic = this.geom.multiLineString(this.points);
|
||||
this.statistics = this.geom.updateStatistics(this.points, geodesic);
|
||||
if (this.options.wrap) {
|
||||
var split = this.geom.splitMultiLineString(geodesic);
|
||||
_super.prototype.setLatLngs.call(this, split);
|
||||
}
|
||||
else {
|
||||
_super.prototype.setLatLngs.call(this, this.geom.wrapMultiLineString(geodesic));
|
||||
}
|
||||
};
|
||||
/**
|
||||
* overwrites the original function with additional functionality to create a geodesic line
|
||||
* @param latlngs an array (or 2d-array) of positions
|
||||
*/
|
||||
GeodesicLine.prototype.setLatLngs = function (latlngs) {
|
||||
this.points = latlngExpressionArraytoLatLngArray(latlngs);
|
||||
this.updateGeometry();
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* add a given point to the geodesic line object
|
||||
* @param latlng point to add. The point will always be added to the last linestring of a multiline
|
||||
* @param latlngs define a linestring to add the new point to. Read from points-property before (e.g. `line.addLatLng(Beijing, line.points[0]);`)
|
||||
*/
|
||||
GeodesicLine.prototype.addLatLng = function (latlng, latlngs) {
|
||||
var point = latlngExpressiontoLatLng(latlng);
|
||||
if (this.points.length === 0) {
|
||||
this.points.push([point]);
|
||||
}
|
||||
else if (latlngs === undefined) {
|
||||
this.points[this.points.length - 1].push(point);
|
||||
}
|
||||
else {
|
||||
latlngs.push(point);
|
||||
}
|
||||
this.updateGeometry();
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Creates geodesic lines from a given GeoJSON-Object.
|
||||
* @param input GeoJSON-Object
|
||||
*/
|
||||
GeodesicLine.prototype.fromGeoJson = function (input) {
|
||||
var latlngs = [];
|
||||
var features = [];
|
||||
if (input.type === "FeatureCollection") {
|
||||
features = input.features;
|
||||
}
|
||||
else if (input.type === "Feature") {
|
||||
features = [input];
|
||||
}
|
||||
else if (["MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon"].includes(input.type)) {
|
||||
features = [
|
||||
{
|
||||
type: "Feature",
|
||||
geometry: input,
|
||||
properties: {}
|
||||
}
|
||||
];
|
||||
}
|
||||
else {
|
||||
console.log("[Leaflet.Geodesic] fromGeoJson() - Type \"".concat(input.type, "\" not supported."));
|
||||
}
|
||||
features.forEach(function (feature) {
|
||||
switch (feature.geometry.type) {
|
||||
case "MultiPoint":
|
||||
case "LineString":
|
||||
latlngs = __spreadArray(__spreadArray([], latlngs, true), [L__namespace.GeoJSON.coordsToLatLngs(feature.geometry.coordinates, 0)], false);
|
||||
break;
|
||||
case "MultiLineString":
|
||||
case "Polygon":
|
||||
latlngs = __spreadArray(__spreadArray([], latlngs, true), L__namespace.GeoJSON.coordsToLatLngs(feature.geometry.coordinates, 1), true);
|
||||
break;
|
||||
case "MultiPolygon":
|
||||
feature.geometry.coordinates.forEach(function (item) {
|
||||
latlngs = __spreadArray(__spreadArray([], latlngs, true), L__namespace.GeoJSON.coordsToLatLngs(item, 1), true);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.log("[Leaflet.Geodesic] fromGeoJson() - Type \"".concat(feature.geometry.type, "\" not supported."));
|
||||
}
|
||||
});
|
||||
if (latlngs.length) {
|
||||
this.setLatLngs(latlngs);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Calculates the distance between two geo-positions
|
||||
* @param start 1st position
|
||||
* @param dest 2nd position
|
||||
* @return the distance in meters
|
||||
*/
|
||||
GeodesicLine.prototype.distance = function (start, dest) {
|
||||
return this.geom.distance(latlngExpressiontoLatLng(start), latlngExpressiontoLatLng(dest));
|
||||
};
|
||||
return GeodesicLine;
|
||||
}(L__namespace.Polyline));
|
||||
|
||||
/**
|
||||
* Can be used to create a geodesic circle based on L.Polyline
|
||||
*/
|
||||
var GeodesicCircleClass = /** @class */ (function (_super) {
|
||||
__extends(GeodesicCircleClass, _super);
|
||||
function GeodesicCircleClass(center, options) {
|
||||
var _a;
|
||||
var _this = _super.call(this, [], options) || this;
|
||||
_this.defaultOptions = { wrap: true, steps: 24, fill: true, noClip: true };
|
||||
_this.statistics = { distanceArray: [], totalDistance: 0, points: 0, vertices: 0 };
|
||||
L__namespace.Util.setOptions(_this, __assign(__assign({}, _this.defaultOptions), options));
|
||||
// merge/set options
|
||||
var extendedOptions = _this.options;
|
||||
_this.radius = (_a = extendedOptions.radius) !== null && _a !== void 0 ? _a : 1000 * 1000;
|
||||
_this.center = center === undefined ? new L__namespace.LatLng(0, 0) : latlngExpressiontoLatLng(center);
|
||||
_this.geom = new GeodesicGeometry(_this.options);
|
||||
// update the geometry
|
||||
_this.update();
|
||||
return _this;
|
||||
}
|
||||
/**
|
||||
* Updates the geometry and re-calculates some statistics
|
||||
*/
|
||||
GeodesicCircleClass.prototype.update = function () {
|
||||
var circle = this.geom.circle(this.center, this.radius);
|
||||
this.statistics = this.geom.updateStatistics([[this.center]], [circle]);
|
||||
// circumfence must be re-calculated from geodesic
|
||||
this.statistics.totalDistance = this.geom.multilineDistance([circle]).reduce(function (x, y) { return x + y; }, 0);
|
||||
if (this.options.wrap) {
|
||||
var split = this.geom.splitCircle(circle);
|
||||
_super.prototype.setLatLngs.call(this, split);
|
||||
}
|
||||
else {
|
||||
_super.prototype.setLatLngs.call(this, circle);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Calculate the distance between the current center and an arbitrary position.
|
||||
* @param latlng geo-position to calculate distance to
|
||||
* @return distance in meters
|
||||
*/
|
||||
GeodesicCircleClass.prototype.distanceTo = function (latlng) {
|
||||
var dest = latlngExpressiontoLatLng(latlng);
|
||||
return this.geom.distance(this.center, dest);
|
||||
};
|
||||
/**
|
||||
* Set a new center for the geodesic circle and update the geometry. Radius may also be set.
|
||||
* @param center the new center
|
||||
* @param radius the new radius
|
||||
*/
|
||||
GeodesicCircleClass.prototype.setLatLng = function (center, radius) {
|
||||
this.center = latlngExpressiontoLatLng(center);
|
||||
this.radius = radius !== null && radius !== void 0 ? radius : this.radius;
|
||||
this.update();
|
||||
};
|
||||
/**
|
||||
* Set a new radius for the geodesic circle and update the geometry. Center may also be set.
|
||||
* @param radius the new radius
|
||||
* @param center the new center
|
||||
*/
|
||||
GeodesicCircleClass.prototype.setRadius = function (radius, center) {
|
||||
this.radius = radius;
|
||||
this.center = center ? latlngExpressiontoLatLng(center) : this.center;
|
||||
this.update();
|
||||
};
|
||||
return GeodesicCircleClass;
|
||||
}(L__namespace.Polyline));
|
||||
|
||||
if (typeof window.L !== "undefined") {
|
||||
window.L.Geodesic = GeodesicLine;
|
||||
window.L.geodesic = function () {
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments[_i];
|
||||
}
|
||||
return new (GeodesicLine.bind.apply(GeodesicLine, __spreadArray([void 0], args, false)))();
|
||||
};
|
||||
window.L.GeodesicCircle = GeodesicCircleClass;
|
||||
window.L.geodesiccircle = function () {
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments[_i];
|
||||
}
|
||||
return new (GeodesicCircleClass.bind.apply(GeodesicCircleClass, __spreadArray([void 0], args, false)))();
|
||||
};
|
||||
}
|
||||
|
||||
exports.GeodesicCircleClass = GeodesicCircleClass;
|
||||
exports.GeodesicLine = GeodesicLine;
|
||||
921
static/leaflet-geodesic/leaflet.geodesic.umd.js
Normal file
921
static/leaflet-geodesic/leaflet.geodesic.umd.js
Normal file
|
|
@ -0,0 +1,921 @@
|
|||
/*! leaflet.geodesic 2.7.1 - (c) Henry Thasler - https://github.com/henrythasler/Leaflet.Geodesic#readme */
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('leaflet')) :
|
||||
typeof define === 'function' && define.amd ? define(['exports', 'leaflet'], factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.L = global.L || {}, global.L.geodesic = {}), global.L));
|
||||
})(this, (function (exports, L) { 'use strict';
|
||||
|
||||
function _interopNamespaceDefault(e) {
|
||||
var n = Object.create(null);
|
||||
if (e) {
|
||||
Object.keys(e).forEach(function (k) {
|
||||
if (k !== 'default') {
|
||||
var d = Object.getOwnPropertyDescriptor(e, k);
|
||||
Object.defineProperty(n, k, d.get ? d : {
|
||||
enumerable: true,
|
||||
get: function () { return e[k]; }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
n.default = e;
|
||||
return Object.freeze(n);
|
||||
}
|
||||
|
||||
var L__namespace = /*#__PURE__*/_interopNamespaceDefault(L);
|
||||
|
||||
/******************************************************************************
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
***************************************************************************** */
|
||||
/* global Reflect, Promise, SuppressedError, Symbol */
|
||||
|
||||
var extendStatics = function(d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
|
||||
function __extends(d, b) {
|
||||
if (typeof b !== "function" && b !== null)
|
||||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
}
|
||||
|
||||
var __assign = function() {
|
||||
__assign = Object.assign || function __assign(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
|
||||
function __spreadArray(to, from, pack) {
|
||||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
||||
if (ar || !(i in from)) {
|
||||
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
||||
ar[i] = from[i];
|
||||
}
|
||||
}
|
||||
return to.concat(ar || Array.prototype.slice.call(from));
|
||||
}
|
||||
|
||||
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
||||
var e = new Error(message);
|
||||
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
||||
};
|
||||
|
||||
var GeodesicCore = /** @class */ (function () {
|
||||
function GeodesicCore(options) {
|
||||
this.options = { wrap: true, steps: 3 };
|
||||
this.ellipsoid = {
|
||||
a: 6378137,
|
||||
b: 6356752.3142,
|
||||
f: 1 / 298.257223563
|
||||
}; // WGS-84
|
||||
this.options = __assign(__assign({}, this.options), options);
|
||||
}
|
||||
GeodesicCore.prototype.toRadians = function (degree) {
|
||||
return (degree * Math.PI) / 180;
|
||||
};
|
||||
GeodesicCore.prototype.toDegrees = function (radians) {
|
||||
return (radians * 180) / Math.PI;
|
||||
};
|
||||
/**
|
||||
* implements scientific modulus
|
||||
* source: http://www.codeavenger.com/2017/05/19/JavaScript-Modulo-operation-and-the-Caesar-Cipher.html
|
||||
* @param n
|
||||
* @param p
|
||||
* @return
|
||||
*/
|
||||
GeodesicCore.prototype.mod = function (n, p) {
|
||||
var r = n % p;
|
||||
return r < 0 ? r + p : r;
|
||||
};
|
||||
/**
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/dms.js
|
||||
* @param degrees arbitrary value
|
||||
* @return degrees between 0..360
|
||||
*/
|
||||
GeodesicCore.prototype.wrap360 = function (degrees) {
|
||||
if (0 <= degrees && degrees < 360) {
|
||||
return degrees; // avoid rounding due to arithmetic ops if within range
|
||||
}
|
||||
else {
|
||||
return this.mod(degrees, 360);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* general wrap function with arbitrary max value
|
||||
* @param degrees arbitrary value
|
||||
* @param max
|
||||
* @return degrees between `-max`..`+max`
|
||||
*/
|
||||
GeodesicCore.prototype.wrap = function (degrees, max) {
|
||||
if (max === void 0) { max = 360; }
|
||||
if (-max <= degrees && degrees <= max) {
|
||||
return degrees;
|
||||
}
|
||||
else {
|
||||
return this.mod(degrees + max, 2 * max) - max;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Vincenty direct calculation.
|
||||
* based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/latlon-ellipsoidal-vincenty.js
|
||||
*
|
||||
* @param start starting point
|
||||
* @param bearing initial bearing (in degrees)
|
||||
* @param distance distance from starting point to calculate along given bearing in meters.
|
||||
* @param maxInterations How many iterations can be made to reach the allowed deviation (`ε`), before an error will be thrown.
|
||||
* @return Final point (destination point) and bearing (in degrees)
|
||||
*/
|
||||
GeodesicCore.prototype.direct = function (start, bearing, distance, maxInterations) {
|
||||
if (maxInterations === void 0) { maxInterations = 100; }
|
||||
var φ1 = this.toRadians(start.lat);
|
||||
var λ1 = this.toRadians(start.lng);
|
||||
var α1 = this.toRadians(bearing);
|
||||
var s = distance;
|
||||
var ε = Number.EPSILON * 1000;
|
||||
var _a = this.ellipsoid, a = _a.a, b = _a.b, f = _a.f;
|
||||
var sinα1 = Math.sin(α1);
|
||||
var cosα1 = Math.cos(α1);
|
||||
var tanU1 = (1 - f) * Math.tan(φ1), cosU1 = 1 / Math.sqrt(1 + tanU1 * tanU1), sinU1 = tanU1 * cosU1;
|
||||
var σ1 = Math.atan2(tanU1, cosα1); // σ1 = angular distance on the sphere from the equator to P1
|
||||
var sinα = cosU1 * sinα1; // α = azimuth of the geodesic at the equator
|
||||
var cosSqα = 1 - sinα * sinα;
|
||||
var uSq = (cosSqα * (a * a - b * b)) / (b * b);
|
||||
var A = 1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
|
||||
var B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
|
||||
var σ = s / (b * A), sinσ = null, cosσ = null, Δσ = null; // σ = angular distance P₁ P₂ on the sphere
|
||||
var cos2σₘ = null; // σₘ = angular distance on the sphere from the equator to the midpoint of the line
|
||||
var σʹ = null, iterations = 0;
|
||||
do {
|
||||
cos2σₘ = Math.cos(2 * σ1 + σ);
|
||||
sinσ = Math.sin(σ);
|
||||
cosσ = Math.cos(σ);
|
||||
Δσ =
|
||||
B *
|
||||
sinσ *
|
||||
(cos2σₘ +
|
||||
(B / 4) *
|
||||
(cosσ * (-1 + 2 * cos2σₘ * cos2σₘ) -
|
||||
(B / 6) * cos2σₘ * (-3 + 4 * sinσ * sinσ) * (-3 + 4 * cos2σₘ * cos2σₘ)));
|
||||
σʹ = σ;
|
||||
σ = s / (b * A) + Δσ;
|
||||
} while (Math.abs(σ - σʹ) > ε && ++iterations < maxInterations);
|
||||
if (iterations >= maxInterations) {
|
||||
throw new EvalError("Direct vincenty formula failed to converge after ".concat(maxInterations, " iterations \n (start=").concat(start.lat, "/").concat(start.lng, "; bearing=").concat(bearing, "; distance=").concat(distance, ")")); // not possible?
|
||||
}
|
||||
var x = sinU1 * sinσ - cosU1 * cosσ * cosα1;
|
||||
var φ2 = Math.atan2(sinU1 * cosσ + cosU1 * sinσ * cosα1, (1 - f) * Math.sqrt(sinα * sinα + x * x));
|
||||
var λ = Math.atan2(sinσ * sinα1, cosU1 * cosσ - sinU1 * sinσ * cosα1);
|
||||
var C = (f / 16) * cosSqα * (4 + f * (4 - 3 * cosSqα));
|
||||
var dL = λ - (1 - C) * f * sinα * (σ + C * sinσ * (cos2σₘ + C * cosσ * (-1 + 2 * cos2σₘ * cos2σₘ)));
|
||||
var λ2 = λ1 + dL;
|
||||
var α2 = Math.atan2(sinα, -x);
|
||||
return {
|
||||
lat: this.toDegrees(φ2),
|
||||
lng: this.toDegrees(λ2),
|
||||
bearing: this.wrap360(this.toDegrees(α2))
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Vincenty inverse calculation.
|
||||
* based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/latlon-ellipsoidal-vincenty.js
|
||||
*
|
||||
* @param start Latitude/longitude of starting point.
|
||||
* @param dest Latitude/longitude of destination point.
|
||||
* @return Object including distance, initialBearing, finalBearing.
|
||||
*/
|
||||
GeodesicCore.prototype.inverse = function (start, dest, maxInterations, mitigateConvergenceError) {
|
||||
if (maxInterations === void 0) { maxInterations = 100; }
|
||||
if (mitigateConvergenceError === void 0) { mitigateConvergenceError = true; }
|
||||
var p1 = start, p2 = dest;
|
||||
var φ1 = this.toRadians(p1.lat), λ1 = this.toRadians(p1.lng);
|
||||
var φ2 = this.toRadians(p2.lat), λ2 = this.toRadians(p2.lng);
|
||||
var π = Math.PI;
|
||||
var ε = Number.EPSILON;
|
||||
// allow alternative ellipsoid to be specified
|
||||
var _a = this.ellipsoid, a = _a.a, b = _a.b, f = _a.f;
|
||||
var dL = λ2 - λ1; // L = difference in longitude, U = reduced latitude, defined by tan U = (1-f)·tanφ.
|
||||
var tanU1 = (1 - f) * Math.tan(φ1), cosU1 = 1 / Math.sqrt(1 + tanU1 * tanU1), sinU1 = tanU1 * cosU1;
|
||||
var tanU2 = (1 - f) * Math.tan(φ2), cosU2 = 1 / Math.sqrt(1 + tanU2 * tanU2), sinU2 = tanU2 * cosU2;
|
||||
var antipodal = Math.abs(dL) > π / 2 || Math.abs(φ2 - φ1) > π / 2;
|
||||
var λ = dL, sinλ = null, cosλ = null; // λ = difference in longitude on an auxiliary sphere
|
||||
var σ = antipodal ? π : 0, sinσ = 0, cosσ = antipodal ? -1 : 1, sinSqσ = null; // σ = angular distance P₁ P₂ on the sphere
|
||||
var cos2σₘ = 1; // σₘ = angular distance on the sphere from the equator to the midpoint of the line
|
||||
var sinα = null, cosSqα = 1; // α = azimuth of the geodesic at the equator
|
||||
var C = null;
|
||||
var λʹ = null, iterations = 0;
|
||||
do {
|
||||
sinλ = Math.sin(λ);
|
||||
cosλ = Math.cos(λ);
|
||||
sinSqσ =
|
||||
cosU2 * sinλ * (cosU2 * sinλ) +
|
||||
(cosU1 * sinU2 - sinU1 * cosU2 * cosλ) * (cosU1 * sinU2 - sinU1 * cosU2 * cosλ);
|
||||
if (Math.abs(sinSqσ) < ε) {
|
||||
break; // co-incident/antipodal points (falls back on λ/σ = L)
|
||||
}
|
||||
sinσ = Math.sqrt(sinSqσ);
|
||||
cosσ = sinU1 * sinU2 + cosU1 * cosU2 * cosλ;
|
||||
σ = Math.atan2(sinσ, cosσ);
|
||||
sinα = (cosU1 * cosU2 * sinλ) / sinσ;
|
||||
cosSqα = 1 - sinα * sinα;
|
||||
cos2σₘ = cosSqα !== 0 ? cosσ - (2 * sinU1 * sinU2) / cosSqα : 0; // on equatorial line cos²α = 0 (§6)
|
||||
C = (f / 16) * cosSqα * (4 + f * (4 - 3 * cosSqα));
|
||||
λʹ = λ;
|
||||
λ = dL + (1 - C) * f * sinα * (σ + C * sinσ * (cos2σₘ + C * cosσ * (-1 + 2 * cos2σₘ * cos2σₘ)));
|
||||
var iterationCheck = antipodal ? Math.abs(λ) - π : Math.abs(λ);
|
||||
if (iterationCheck > π) {
|
||||
throw new EvalError("λ > π");
|
||||
}
|
||||
} while (Math.abs(λ - λʹ) > 1e-12 && ++iterations < maxInterations);
|
||||
if (iterations >= maxInterations) {
|
||||
if (mitigateConvergenceError) {
|
||||
return this.inverse(start, new L__namespace.LatLng(dest.lat, dest.lng - 0.01), maxInterations, mitigateConvergenceError);
|
||||
}
|
||||
else {
|
||||
throw new EvalError("Inverse vincenty formula failed to converge after ".concat(maxInterations, " iterations \n (start=").concat(start.lat, "/").concat(start.lng, "; dest=").concat(dest.lat, "/").concat(dest.lng, ")"));
|
||||
}
|
||||
}
|
||||
var uSq = (cosSqα * (a * a - b * b)) / (b * b);
|
||||
var A = 1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
|
||||
var B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
|
||||
var Δσ = B *
|
||||
sinσ *
|
||||
(cos2σₘ +
|
||||
(B / 4) *
|
||||
(cosσ * (-1 + 2 * cos2σₘ * cos2σₘ) -
|
||||
(B / 6) * cos2σₘ * (-3 + 4 * sinσ * sinσ) * (-3 + 4 * cos2σₘ * cos2σₘ)));
|
||||
var s = b * A * (σ - Δσ); // s = length of the geodesic
|
||||
// note special handling of exactly antipodal points where sin²σ = 0 (due to discontinuity
|
||||
// atan2(0, 0) = 0 but atan2(this.ε, 0) = π/2 / 90°) - in which case bearing is always meridional,
|
||||
// due north (or due south!)
|
||||
// α = azimuths of the geodesic; α2 the direction P₁ P₂ produced
|
||||
var α1 = Math.abs(sinSqσ) < ε ? 0 : Math.atan2(cosU2 * sinλ, cosU1 * sinU2 - sinU1 * cosU2 * cosλ);
|
||||
var α2 = Math.abs(sinSqσ) < ε ? π : Math.atan2(cosU1 * sinλ, -sinU1 * cosU2 + cosU1 * sinU2 * cosλ);
|
||||
return {
|
||||
distance: s,
|
||||
initialBearing: Math.abs(s) < ε ? NaN : this.wrap360(this.toDegrees(α1)),
|
||||
finalBearing: Math.abs(s) < ε ? NaN : this.wrap360(this.toDegrees(α2))
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Returns the point of intersection of two paths defined by position and bearing.
|
||||
* This calculation uses a spherical model of the earth. This will lead to small errors compared to an ellipsiod model.
|
||||
* based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
|
||||
* source: https://github.com/chrisveness/geodesy/blob/master/latlon-spherical.js
|
||||
*
|
||||
* @param firstPos 1st path: position and bearing
|
||||
* @param firstBearing
|
||||
* @param secondPos 2nd path: position and bearing
|
||||
* @param secondBearing
|
||||
*/
|
||||
GeodesicCore.prototype.intersection = function (firstPos, firstBearing, secondPos, secondBearing) {
|
||||
var φ1 = this.toRadians(firstPos.lat);
|
||||
var λ1 = this.toRadians(firstPos.lng);
|
||||
var φ2 = this.toRadians(secondPos.lat);
|
||||
var λ2 = this.toRadians(secondPos.lng);
|
||||
var θ13 = this.toRadians(firstBearing);
|
||||
var θ23 = this.toRadians(secondBearing);
|
||||
var Δφ = φ2 - φ1, Δλ = λ2 - λ1;
|
||||
var π = Math.PI;
|
||||
var ε = Number.EPSILON;
|
||||
// angular distance p1-p2
|
||||
var δ12 = 2 *
|
||||
Math.asin(Math.sqrt(Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
|
||||
Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2)));
|
||||
if (Math.abs(δ12) < ε) {
|
||||
return firstPos; // coincident points
|
||||
}
|
||||
// initial/final bearings between points
|
||||
var cosθa = (Math.sin(φ2) - Math.sin(φ1) * Math.cos(δ12)) / (Math.sin(δ12) * Math.cos(φ1));
|
||||
var cosθb = (Math.sin(φ1) - Math.sin(φ2) * Math.cos(δ12)) / (Math.sin(δ12) * Math.cos(φ2));
|
||||
var θa = Math.acos(Math.min(Math.max(cosθa, -1), 1)); // protect against rounding errors
|
||||
var θb = Math.acos(Math.min(Math.max(cosθb, -1), 1)); // protect against rounding errors
|
||||
var θ12 = Math.sin(λ2 - λ1) > 0 ? θa : 2 * π - θa;
|
||||
var θ21 = Math.sin(λ2 - λ1) > 0 ? 2 * π - θb : θb;
|
||||
var α1 = θ13 - θ12; // angle 2-1-3
|
||||
var α2 = θ21 - θ23; // angle 1-2-3
|
||||
if (Math.sin(α1) === 0 && Math.sin(α2) === 0) {
|
||||
return null; // infinite intersections
|
||||
}
|
||||
if (Math.sin(α1) * Math.sin(α2) < 0) {
|
||||
return null; // ambiguous intersection (antipodal?)
|
||||
}
|
||||
var cosα3 = -Math.cos(α1) * Math.cos(α2) + Math.sin(α1) * Math.sin(α2) * Math.cos(δ12);
|
||||
var δ13 = Math.atan2(Math.sin(δ12) * Math.sin(α1) * Math.sin(α2), Math.cos(α2) + Math.cos(α1) * cosα3);
|
||||
var φ3 = Math.asin(Math.min(Math.max(Math.sin(φ1) * Math.cos(δ13) + Math.cos(φ1) * Math.sin(δ13) * Math.cos(θ13), -1), 1));
|
||||
var Δλ13 = Math.atan2(Math.sin(θ13) * Math.sin(δ13) * Math.cos(φ1), Math.cos(δ13) - Math.sin(φ1) * Math.sin(φ3));
|
||||
var λ3 = λ1 + Δλ13;
|
||||
return new L__namespace.LatLng(this.toDegrees(φ3), this.toDegrees(λ3));
|
||||
};
|
||||
GeodesicCore.prototype.midpoint = function (start, dest) {
|
||||
// φm = atan2( sinφ1 + sinφ2, √( (cosφ1 + cosφ2⋅cosΔλ)² + cos²φ2⋅sin²Δλ ) )
|
||||
// λm = λ1 + atan2(cosφ2⋅sinΔλ, cosφ1 + cosφ2⋅cosΔλ)
|
||||
// midpoint is sum of vectors to two points: mathforum.org/library/drmath/view/51822.html
|
||||
var φ1 = this.toRadians(start.lat);
|
||||
var λ1 = this.toRadians(start.lng);
|
||||
var φ2 = this.toRadians(dest.lat);
|
||||
var Δλ = this.toRadians(dest.lng - start.lng);
|
||||
// get cartesian coordinates for the two points
|
||||
var A = { x: Math.cos(φ1), y: 0, z: Math.sin(φ1) }; // place point A on prime meridian y=0
|
||||
var B = { x: Math.cos(φ2) * Math.cos(Δλ), y: Math.cos(φ2) * Math.sin(Δλ), z: Math.sin(φ2) };
|
||||
// vector to midpoint is sum of vectors to two points (no need to normalise)
|
||||
var C = { x: A.x + B.x, y: A.y + B.y, z: A.z + B.z };
|
||||
var φm = Math.atan2(C.z, Math.sqrt(C.x * C.x + C.y * C.y));
|
||||
var λm = λ1 + Math.atan2(C.y, C.x);
|
||||
return new L__namespace.LatLng(this.toDegrees(φm), this.toDegrees(λm));
|
||||
};
|
||||
return GeodesicCore;
|
||||
}());
|
||||
|
||||
var GeodesicGeometry = /** @class */ (function () {
|
||||
function GeodesicGeometry(options) {
|
||||
var _a;
|
||||
this.geodesic = new GeodesicCore();
|
||||
this.steps = (_a = options === null || options === void 0 ? void 0 : options.steps) !== null && _a !== void 0 ? _a : 3;
|
||||
}
|
||||
/**
|
||||
* A geodesic line between `start` and `dest` is created with this recursive function.
|
||||
* It calculates the geodesic midpoint between `start` and `dest` and uses this midpoint to call itself again (twice!).
|
||||
* The results are then merged into one continuous linestring.
|
||||
*
|
||||
* The number of resulting vertices (incl. `start` and `dest`) depends on the initial value for `iterations`
|
||||
* and can be calculated with: vertices == 1 + 2 ** (initialIterations + 1)
|
||||
*
|
||||
* As this is an exponential function, be extra careful to limit the initial value for `iterations` (8 results in 513 vertices).
|
||||
*
|
||||
* @param start start position
|
||||
* @param dest destination
|
||||
* @param iterations
|
||||
* @return resulting linestring
|
||||
*/
|
||||
GeodesicGeometry.prototype.recursiveMidpoint = function (start, dest, iterations) {
|
||||
var geom = [start, dest];
|
||||
var midpoint = this.geodesic.midpoint(start, dest);
|
||||
if (iterations > 0) {
|
||||
geom.splice.apply(geom, __spreadArray([0, 1], this.recursiveMidpoint(start, midpoint, iterations - 1), false));
|
||||
geom.splice.apply(geom, __spreadArray([geom.length - 2, 2], this.recursiveMidpoint(midpoint, dest, iterations - 1), false));
|
||||
}
|
||||
else {
|
||||
geom.splice(1, 0, midpoint);
|
||||
}
|
||||
return geom;
|
||||
};
|
||||
/**
|
||||
* This is the wrapper-function to generate a geodesic line. It's just for future backwards-compatibility
|
||||
* if there is another algorithm used to create the actual line.
|
||||
*
|
||||
* The `steps`-property is used to define the number of resulting vertices of the linestring: vertices == 1 + 2 ** (steps + 1)
|
||||
* The value for `steps` is currently limited to 8 (513 vertices) for performance reasons until another algorithm is found.
|
||||
*
|
||||
* @param start start position
|
||||
* @param dest destination
|
||||
* @return resulting linestring
|
||||
*/
|
||||
GeodesicGeometry.prototype.line = function (start, dest) {
|
||||
return this.recursiveMidpoint(start, dest, Math.min(8, this.steps));
|
||||
};
|
||||
GeodesicGeometry.prototype.multiLineString = function (latlngs) {
|
||||
var multiLineString = [];
|
||||
for (var _i = 0, latlngs_1 = latlngs; _i < latlngs_1.length; _i++) {
|
||||
var linestring = latlngs_1[_i];
|
||||
var segment = [];
|
||||
for (var j = 1; j < linestring.length; j++) {
|
||||
segment.splice.apply(segment, __spreadArray([segment.length - 1, 1], this.line(linestring[j - 1], linestring[j]), false));
|
||||
}
|
||||
multiLineString.push(segment);
|
||||
}
|
||||
return multiLineString;
|
||||
};
|
||||
GeodesicGeometry.prototype.lineString = function (latlngs) {
|
||||
return this.multiLineString([latlngs])[0];
|
||||
};
|
||||
/**
|
||||
*
|
||||
* Is much (10x) faster than the previous implementation:
|
||||
*
|
||||
* ```
|
||||
* Benchmark (no split): splitLine x 459,044 ops/sec ±0.53% (95 runs sampled)
|
||||
* Benchmark (split): splitLine x 42,999 ops/sec ±0.51% (97 runs sampled)
|
||||
* ```
|
||||
*
|
||||
* @param startPosition
|
||||
* @param destPosition
|
||||
*/
|
||||
GeodesicGeometry.prototype.splitLine = function (startPosition, destPosition) {
|
||||
var antimeridianWest = {
|
||||
point: new L__namespace.LatLng(89.9, -180.0000001),
|
||||
bearing: 180
|
||||
};
|
||||
var antimeridianEast = {
|
||||
point: new L__namespace.LatLng(89.9, 180.0000001),
|
||||
bearing: 180
|
||||
};
|
||||
// make a copy to work with
|
||||
var start = new L__namespace.LatLng(startPosition.lat, startPosition.lng, startPosition.alt);
|
||||
var dest = new L__namespace.LatLng(destPosition.lat, destPosition.lng, destPosition.alt);
|
||||
start.lng = this.geodesic.wrap(start.lng, 360);
|
||||
dest.lng = this.geodesic.wrap(dest.lng, 360);
|
||||
if (dest.lng - start.lng > 180) {
|
||||
dest.lng = dest.lng - 360;
|
||||
}
|
||||
else if (dest.lng - start.lng < -180) {
|
||||
dest.lng = dest.lng + 360;
|
||||
}
|
||||
var result = [
|
||||
[
|
||||
new L__namespace.LatLng(start.lat, this.geodesic.wrap(start.lng, 180), start.alt),
|
||||
new L__namespace.LatLng(dest.lat, this.geodesic.wrap(dest.lng, 180), dest.alt)
|
||||
]
|
||||
];
|
||||
// crossing antimeridian from "this" side?
|
||||
if (start.lng >= -180 && start.lng <= 180) {
|
||||
// crossing the "western" antimeridian
|
||||
if (dest.lng < -180) {
|
||||
var bearing = this.geodesic.inverse(start, dest).initialBearing;
|
||||
var intersection = this.geodesic.intersection(start, bearing, antimeridianWest.point, antimeridianWest.bearing);
|
||||
if (intersection) {
|
||||
result = [
|
||||
[start, intersection],
|
||||
[
|
||||
new L__namespace.LatLng(intersection.lat, intersection.lng + 360),
|
||||
new L__namespace.LatLng(dest.lat, dest.lng + 360, dest.alt)
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
// crossing the "eastern" antimeridian
|
||||
else if (dest.lng > 180) {
|
||||
var bearing = this.geodesic.inverse(start, dest).initialBearing;
|
||||
var intersection = this.geodesic.intersection(start, bearing, antimeridianEast.point, antimeridianEast.bearing);
|
||||
if (intersection) {
|
||||
result = [
|
||||
[start, intersection],
|
||||
[
|
||||
new L__namespace.LatLng(intersection.lat, intersection.lng - 360),
|
||||
new L__namespace.LatLng(dest.lat, dest.lng - 360, dest.alt)
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
// coming back over the antimeridian from the "other" side?
|
||||
else if (dest.lng >= -180 && dest.lng <= 180) {
|
||||
// crossing the "western" antimeridian
|
||||
if (start.lng < -180) {
|
||||
var bearing = this.geodesic.inverse(start, dest).initialBearing;
|
||||
var intersection = this.geodesic.intersection(start, bearing, antimeridianWest.point, antimeridianWest.bearing);
|
||||
if (intersection) {
|
||||
result = [
|
||||
[
|
||||
new L__namespace.LatLng(start.lat, start.lng + 360, start.alt),
|
||||
new L__namespace.LatLng(intersection.lat, intersection.lng + 360)
|
||||
],
|
||||
[intersection, dest]
|
||||
];
|
||||
}
|
||||
}
|
||||
// crossing the "eastern" antimeridian
|
||||
else if (start.lng > 180) {
|
||||
var bearing = this.geodesic.inverse(start, dest).initialBearing;
|
||||
var intersection = this.geodesic.intersection(start, bearing, antimeridianWest.point, antimeridianWest.bearing);
|
||||
if (intersection) {
|
||||
result = [
|
||||
[
|
||||
new L__namespace.LatLng(start.lat, start.lng - 360, start.alt),
|
||||
new L__namespace.LatLng(intersection.lat, intersection.lng - 360)
|
||||
],
|
||||
[intersection, dest]
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/**
|
||||
* Linestrings of a given multilinestring that cross the antimeridian will be split in two separate linestrings.
|
||||
* This function is used to wrap lines around when they cross the antimeridian
|
||||
* It iterates over all linestrings and reconstructs the step-by-step if no split is needed.
|
||||
* In case the line was split, the linestring ends at the antimeridian and a new linestring is created for the
|
||||
* remaining points of the original linestring.
|
||||
*
|
||||
* @param multilinestring
|
||||
* @return another multilinestring where segments crossing the antimeridian are split
|
||||
*/
|
||||
GeodesicGeometry.prototype.splitMultiLineString = function (multilinestring) {
|
||||
var result = [];
|
||||
for (var _i = 0, multilinestring_1 = multilinestring; _i < multilinestring_1.length; _i++) {
|
||||
var linestring = multilinestring_1[_i];
|
||||
if (linestring.length === 1) {
|
||||
result.push(linestring); // just a single point in linestring, no need to split
|
||||
continue;
|
||||
}
|
||||
var segment = [];
|
||||
for (var j = 1; j < linestring.length; j++) {
|
||||
var split = this.splitLine(linestring[j - 1], linestring[j]);
|
||||
segment.pop();
|
||||
segment = segment.concat(split[0]);
|
||||
if (split.length > 1) {
|
||||
result.push(segment); // the line was split, so we end the linestring right here
|
||||
segment = split[1]; // begin the new linestring with the second part of the split line
|
||||
}
|
||||
}
|
||||
result.push(segment);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/**
|
||||
* Linestrings of a given multilinestring will be wrapped (+- 360°) to show a continuous line w/o any weird discontinuities
|
||||
* when `wrap` is set to `false` in the geodesic class
|
||||
* @param multilinestring
|
||||
* @returns another multilinestring where the points of each linestring are wrapped accordingly
|
||||
*/
|
||||
GeodesicGeometry.prototype.wrapMultiLineString = function (multilinestring) {
|
||||
var result = [];
|
||||
for (var _i = 0, multilinestring_2 = multilinestring; _i < multilinestring_2.length; _i++) {
|
||||
var linestring = multilinestring_2[_i];
|
||||
var resultLine = [];
|
||||
var previous = null;
|
||||
// iterate over every point and check if it needs to be wrapped
|
||||
for (var _a = 0, linestring_1 = linestring; _a < linestring_1.length; _a++) {
|
||||
var point = linestring_1[_a];
|
||||
if (previous === null) {
|
||||
// the first point is the anchor of the linestring from which the line will always start (w/o any wrapping applied)
|
||||
resultLine.push(new L__namespace.LatLng(point.lat, point.lng));
|
||||
previous = new L__namespace.LatLng(point.lat, point.lng);
|
||||
}
|
||||
else {
|
||||
// I prefer clearly defined branches over a continue-operation.
|
||||
// if the difference between the current and *previous* point is greater than 360°, the current point needs to be shifted
|
||||
// to be on the same 'sphere' as the previous one.
|
||||
var offset = Math.round((point.lng - previous.lng) / 360);
|
||||
// shift the point accordingly and add to the result
|
||||
resultLine.push(new L__namespace.LatLng(point.lat, point.lng - offset * 360));
|
||||
// use the wrapped point as the anchor for the next one
|
||||
previous = new L__namespace.LatLng(point.lat, point.lng - offset * 360); // Need a new object here, to avoid changing the input data
|
||||
}
|
||||
}
|
||||
result.push(resultLine);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/**
|
||||
* Creates a circular (constant radius), closed (1st pos == last pos) geodesic linestring.
|
||||
* The number of vertices is calculated with: `vertices == steps + 1` (where 1st == last)
|
||||
*
|
||||
* @param center
|
||||
* @param radius
|
||||
* @return resulting linestring
|
||||
*/
|
||||
GeodesicGeometry.prototype.circle = function (center, radius) {
|
||||
var vertices = [];
|
||||
for (var i = 0; i < this.steps; i++) {
|
||||
var point = this.geodesic.direct(center, (360 / this.steps) * i, radius);
|
||||
vertices.push(new L__namespace.LatLng(point.lat, point.lng));
|
||||
}
|
||||
// append first vertice to the end to close the linestring
|
||||
vertices.push(new L__namespace.LatLng(vertices[0].lat, vertices[0].lng));
|
||||
return vertices;
|
||||
};
|
||||
/**
|
||||
* Handles splitting of circles at the antimeridian.
|
||||
* @param linestring a linestring that resembles the geodesic circle
|
||||
* @return a multilinestring that consist of one or two linestrings
|
||||
*/
|
||||
GeodesicGeometry.prototype.splitCircle = function (linestring) {
|
||||
var result = this.splitMultiLineString([linestring]);
|
||||
// If the circle was split, it results in exactly three linestrings where first and last
|
||||
// must be re-assembled because they belong to the same "side" of the split circle.
|
||||
if (result.length === 3) {
|
||||
result[2] = __spreadArray(__spreadArray([], result[2], true), result[0], true);
|
||||
result.shift();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/**
|
||||
* Calculates the distance between two positions on the earths surface
|
||||
* @param start 1st position
|
||||
* @param dest 2nd position
|
||||
* @return the distance in **meters**
|
||||
*/
|
||||
GeodesicGeometry.prototype.distance = function (start, dest) {
|
||||
return this.geodesic.inverse(new L__namespace.LatLng(start.lat, this.geodesic.wrap(start.lng, 180)), new L__namespace.LatLng(dest.lat, this.geodesic.wrap(dest.lng, 180))).distance;
|
||||
};
|
||||
GeodesicGeometry.prototype.multilineDistance = function (multilinestring) {
|
||||
var dist = [];
|
||||
for (var _i = 0, multilinestring_3 = multilinestring; _i < multilinestring_3.length; _i++) {
|
||||
var linestring = multilinestring_3[_i];
|
||||
var segmentDistance = 0;
|
||||
for (var j = 1; j < linestring.length; j++) {
|
||||
segmentDistance += this.distance(linestring[j - 1], linestring[j]);
|
||||
}
|
||||
dist.push(segmentDistance);
|
||||
}
|
||||
return dist;
|
||||
};
|
||||
GeodesicGeometry.prototype.updateStatistics = function (points, vertices) {
|
||||
var stats = { distanceArray: [], totalDistance: 0, points: 0, vertices: 0 };
|
||||
stats.distanceArray = this.multilineDistance(points);
|
||||
stats.totalDistance = stats.distanceArray.reduce(function (x, y) { return x + y; }, 0);
|
||||
stats.points = 0;
|
||||
for (var _i = 0, points_1 = points; _i < points_1.length; _i++) {
|
||||
var item = points_1[_i];
|
||||
stats.points += item.reduce(function (x) { return x + 1; }, 0);
|
||||
}
|
||||
stats.vertices = 0;
|
||||
for (var _a = 0, vertices_1 = vertices; _a < vertices_1.length; _a++) {
|
||||
var item = vertices_1[_a];
|
||||
stats.vertices += item.reduce(function (x) { return x + 1; }, 0);
|
||||
}
|
||||
return stats;
|
||||
};
|
||||
return GeodesicGeometry;
|
||||
}());
|
||||
|
||||
function instanceOfLatLngLiteral(object) {
|
||||
return ((typeof object === "object")
|
||||
&& (object !== null)
|
||||
&& ("lat" in object)
|
||||
&& ("lng" in object)
|
||||
&& (typeof object.lat === "number")
|
||||
&& (typeof object.lng === "number"));
|
||||
}
|
||||
function instanceOfLatLngTuple(object) {
|
||||
return ((object instanceof Array)
|
||||
&& (typeof object[0] === "number")
|
||||
&& (typeof object[1] === "number"));
|
||||
}
|
||||
function instanceOfLatLngExpression(object) {
|
||||
return object instanceof L__namespace.LatLng || instanceOfLatLngTuple(object) || instanceOfLatLngLiteral(object);
|
||||
}
|
||||
function latlngExpressiontoLatLng(input) {
|
||||
if (input instanceof L__namespace.LatLng) {
|
||||
return input;
|
||||
}
|
||||
else if (instanceOfLatLngTuple(input)) {
|
||||
return new L__namespace.LatLng(input[0], input[1], input.at(2)); // alt is optional
|
||||
}
|
||||
else if (instanceOfLatLngLiteral(input)) {
|
||||
return new L__namespace.LatLng(input.lat, input.lng, input.alt);
|
||||
}
|
||||
throw new Error("L.LatLngExpression expected. Unknown object found.");
|
||||
}
|
||||
function latlngExpressionArraytoLatLngArray(input) {
|
||||
var latlng = [];
|
||||
var iterateOver = instanceOfLatLngExpression(input[0]) ? [input] : input;
|
||||
var unknownObjectError = new Error("L.LatLngExpression[] | L.LatLngExpression[][] expected. Unknown object found.");
|
||||
if (!(iterateOver instanceof Array)) {
|
||||
throw unknownObjectError;
|
||||
}
|
||||
for (var _i = 0, _a = iterateOver; _i < _a.length; _i++) {
|
||||
var group = _a[_i];
|
||||
if (!(group instanceof Array)) {
|
||||
throw unknownObjectError;
|
||||
}
|
||||
var sub = [];
|
||||
for (var _b = 0, group_1 = group; _b < group_1.length; _b++) {
|
||||
var point = group_1[_b];
|
||||
if (!instanceOfLatLngExpression(point)) {
|
||||
throw unknownObjectError;
|
||||
}
|
||||
sub.push(latlngExpressiontoLatLng(point));
|
||||
}
|
||||
latlng.push(sub);
|
||||
}
|
||||
return latlng;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw geodesic lines based on L.Polyline
|
||||
*/
|
||||
var GeodesicLine = /** @class */ (function (_super) {
|
||||
__extends(GeodesicLine, _super);
|
||||
function GeodesicLine(latlngs, options) {
|
||||
var _this = _super.call(this, [], options) || this;
|
||||
/** these should be good for most use-cases */
|
||||
_this.defaultOptions = { wrap: true, steps: 3 };
|
||||
/** use this if you need some detailled info about the current geometry */
|
||||
_this.statistics = { distanceArray: [], totalDistance: 0, points: 0, vertices: 0 };
|
||||
/** stores all positions that are used to create the geodesic line */
|
||||
_this.points = [];
|
||||
L__namespace.Util.setOptions(_this, __assign(__assign({}, _this.defaultOptions), options));
|
||||
_this.geom = new GeodesicGeometry(_this.options);
|
||||
if (latlngs !== undefined) {
|
||||
_this.setLatLngs(latlngs);
|
||||
}
|
||||
return _this;
|
||||
}
|
||||
/** calculates the geodesics and update the polyline-object accordingly */
|
||||
GeodesicLine.prototype.updateGeometry = function () {
|
||||
var geodesic = [];
|
||||
geodesic = this.geom.multiLineString(this.points);
|
||||
this.statistics = this.geom.updateStatistics(this.points, geodesic);
|
||||
if (this.options.wrap) {
|
||||
var split = this.geom.splitMultiLineString(geodesic);
|
||||
_super.prototype.setLatLngs.call(this, split);
|
||||
}
|
||||
else {
|
||||
_super.prototype.setLatLngs.call(this, this.geom.wrapMultiLineString(geodesic));
|
||||
}
|
||||
};
|
||||
/**
|
||||
* overwrites the original function with additional functionality to create a geodesic line
|
||||
* @param latlngs an array (or 2d-array) of positions
|
||||
*/
|
||||
GeodesicLine.prototype.setLatLngs = function (latlngs) {
|
||||
this.points = latlngExpressionArraytoLatLngArray(latlngs);
|
||||
this.updateGeometry();
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* add a given point to the geodesic line object
|
||||
* @param latlng point to add. The point will always be added to the last linestring of a multiline
|
||||
* @param latlngs define a linestring to add the new point to. Read from points-property before (e.g. `line.addLatLng(Beijing, line.points[0]);`)
|
||||
*/
|
||||
GeodesicLine.prototype.addLatLng = function (latlng, latlngs) {
|
||||
var point = latlngExpressiontoLatLng(latlng);
|
||||
if (this.points.length === 0) {
|
||||
this.points.push([point]);
|
||||
}
|
||||
else if (latlngs === undefined) {
|
||||
this.points[this.points.length - 1].push(point);
|
||||
}
|
||||
else {
|
||||
latlngs.push(point);
|
||||
}
|
||||
this.updateGeometry();
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Creates geodesic lines from a given GeoJSON-Object.
|
||||
* @param input GeoJSON-Object
|
||||
*/
|
||||
GeodesicLine.prototype.fromGeoJson = function (input) {
|
||||
var latlngs = [];
|
||||
var features = [];
|
||||
if (input.type === "FeatureCollection") {
|
||||
features = input.features;
|
||||
}
|
||||
else if (input.type === "Feature") {
|
||||
features = [input];
|
||||
}
|
||||
else if (["MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon"].includes(input.type)) {
|
||||
features = [
|
||||
{
|
||||
type: "Feature",
|
||||
geometry: input,
|
||||
properties: {}
|
||||
}
|
||||
];
|
||||
}
|
||||
else {
|
||||
console.log("[Leaflet.Geodesic] fromGeoJson() - Type \"".concat(input.type, "\" not supported."));
|
||||
}
|
||||
features.forEach(function (feature) {
|
||||
switch (feature.geometry.type) {
|
||||
case "MultiPoint":
|
||||
case "LineString":
|
||||
latlngs = __spreadArray(__spreadArray([], latlngs, true), [L__namespace.GeoJSON.coordsToLatLngs(feature.geometry.coordinates, 0)], false);
|
||||
break;
|
||||
case "MultiLineString":
|
||||
case "Polygon":
|
||||
latlngs = __spreadArray(__spreadArray([], latlngs, true), L__namespace.GeoJSON.coordsToLatLngs(feature.geometry.coordinates, 1), true);
|
||||
break;
|
||||
case "MultiPolygon":
|
||||
feature.geometry.coordinates.forEach(function (item) {
|
||||
latlngs = __spreadArray(__spreadArray([], latlngs, true), L__namespace.GeoJSON.coordsToLatLngs(item, 1), true);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.log("[Leaflet.Geodesic] fromGeoJson() - Type \"".concat(feature.geometry.type, "\" not supported."));
|
||||
}
|
||||
});
|
||||
if (latlngs.length) {
|
||||
this.setLatLngs(latlngs);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
/**
|
||||
* Calculates the distance between two geo-positions
|
||||
* @param start 1st position
|
||||
* @param dest 2nd position
|
||||
* @return the distance in meters
|
||||
*/
|
||||
GeodesicLine.prototype.distance = function (start, dest) {
|
||||
return this.geom.distance(latlngExpressiontoLatLng(start), latlngExpressiontoLatLng(dest));
|
||||
};
|
||||
return GeodesicLine;
|
||||
}(L__namespace.Polyline));
|
||||
|
||||
/**
|
||||
* Can be used to create a geodesic circle based on L.Polyline
|
||||
*/
|
||||
var GeodesicCircleClass = /** @class */ (function (_super) {
|
||||
__extends(GeodesicCircleClass, _super);
|
||||
function GeodesicCircleClass(center, options) {
|
||||
var _a;
|
||||
var _this = _super.call(this, [], options) || this;
|
||||
_this.defaultOptions = { wrap: true, steps: 24, fill: true, noClip: true };
|
||||
_this.statistics = { distanceArray: [], totalDistance: 0, points: 0, vertices: 0 };
|
||||
L__namespace.Util.setOptions(_this, __assign(__assign({}, _this.defaultOptions), options));
|
||||
// merge/set options
|
||||
var extendedOptions = _this.options;
|
||||
_this.radius = (_a = extendedOptions.radius) !== null && _a !== void 0 ? _a : 1000 * 1000;
|
||||
_this.center = center === undefined ? new L__namespace.LatLng(0, 0) : latlngExpressiontoLatLng(center);
|
||||
_this.geom = new GeodesicGeometry(_this.options);
|
||||
// update the geometry
|
||||
_this.update();
|
||||
return _this;
|
||||
}
|
||||
/**
|
||||
* Updates the geometry and re-calculates some statistics
|
||||
*/
|
||||
GeodesicCircleClass.prototype.update = function () {
|
||||
var circle = this.geom.circle(this.center, this.radius);
|
||||
this.statistics = this.geom.updateStatistics([[this.center]], [circle]);
|
||||
// circumfence must be re-calculated from geodesic
|
||||
this.statistics.totalDistance = this.geom.multilineDistance([circle]).reduce(function (x, y) { return x + y; }, 0);
|
||||
if (this.options.wrap) {
|
||||
var split = this.geom.splitCircle(circle);
|
||||
_super.prototype.setLatLngs.call(this, split);
|
||||
}
|
||||
else {
|
||||
_super.prototype.setLatLngs.call(this, circle);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Calculate the distance between the current center and an arbitrary position.
|
||||
* @param latlng geo-position to calculate distance to
|
||||
* @return distance in meters
|
||||
*/
|
||||
GeodesicCircleClass.prototype.distanceTo = function (latlng) {
|
||||
var dest = latlngExpressiontoLatLng(latlng);
|
||||
return this.geom.distance(this.center, dest);
|
||||
};
|
||||
/**
|
||||
* Set a new center for the geodesic circle and update the geometry. Radius may also be set.
|
||||
* @param center the new center
|
||||
* @param radius the new radius
|
||||
*/
|
||||
GeodesicCircleClass.prototype.setLatLng = function (center, radius) {
|
||||
this.center = latlngExpressiontoLatLng(center);
|
||||
this.radius = radius !== null && radius !== void 0 ? radius : this.radius;
|
||||
this.update();
|
||||
};
|
||||
/**
|
||||
* Set a new radius for the geodesic circle and update the geometry. Center may also be set.
|
||||
* @param radius the new radius
|
||||
* @param center the new center
|
||||
*/
|
||||
GeodesicCircleClass.prototype.setRadius = function (radius, center) {
|
||||
this.radius = radius;
|
||||
this.center = center ? latlngExpressiontoLatLng(center) : this.center;
|
||||
this.update();
|
||||
};
|
||||
return GeodesicCircleClass;
|
||||
}(L__namespace.Polyline));
|
||||
|
||||
if (typeof window.L !== "undefined") {
|
||||
window.L.Geodesic = GeodesicLine;
|
||||
window.L.geodesic = function () {
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments[_i];
|
||||
}
|
||||
return new (GeodesicLine.bind.apply(GeodesicLine, __spreadArray([void 0], args, false)))();
|
||||
};
|
||||
window.L.GeodesicCircle = GeodesicCircleClass;
|
||||
window.L.geodesiccircle = function () {
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments[_i];
|
||||
}
|
||||
return new (GeodesicCircleClass.bind.apply(GeodesicCircleClass, __spreadArray([void 0], args, false)))();
|
||||
};
|
||||
}
|
||||
|
||||
exports.GeodesicCircleClass = GeodesicCircleClass;
|
||||
exports.GeodesicLine = GeodesicLine;
|
||||
|
||||
}));
|
||||
4838
static/leaflet-geodesic/leaflet.geodesic.umd.js.stats.html
Normal file
4838
static/leaflet-geodesic/leaflet.geodesic.umd.js.stats.html
Normal file
File diff suppressed because one or more lines are too long
2
static/leaflet-geodesic/leaflet.geodesic.umd.min.js
vendored
Normal file
2
static/leaflet-geodesic/leaflet.geodesic.umd.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1 @@
|
|||
iaFsrOsrVQKaxgOutC3x1hPWfg3K6DjcKZrxchqbO8amLrjJyYw7/ukh3ar4kly4kK2m5z5qiB3+Dt5RI5Pq4g==
|
||||
BIN
static/leaflet/images/layers-2x.png
Normal file
BIN
static/leaflet/images/layers-2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
static/leaflet/images/layers.png
Normal file
BIN
static/leaflet/images/layers.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 696 B |
BIN
static/leaflet/images/marker-icon-2x.png
Normal file
BIN
static/leaflet/images/marker-icon-2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
static/leaflet/images/marker-icon.png
Normal file
BIN
static/leaflet/images/marker-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
static/leaflet/images/marker-shadow.png
Normal file
BIN
static/leaflet/images/marker-shadow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 618 B |
14419
static/leaflet/leaflet-src.esm.js
Normal file
14419
static/leaflet/leaflet-src.esm.js
Normal file
File diff suppressed because it is too large
Load diff
1
static/leaflet/leaflet-src.esm.js.map
Normal file
1
static/leaflet/leaflet-src.esm.js.map
Normal file
File diff suppressed because one or more lines are too long
14512
static/leaflet/leaflet-src.js
Normal file
14512
static/leaflet/leaflet-src.js
Normal file
File diff suppressed because it is too large
Load diff
1
static/leaflet/leaflet-src.js.map
Normal file
1
static/leaflet/leaflet-src.js.map
Normal file
File diff suppressed because one or more lines are too long
661
static/leaflet/leaflet.css
Normal file
661
static/leaflet/leaflet.css
Normal file
|
|
@ -0,0 +1,661 @@
|
|||
/* required styles */
|
||||
|
||||
.leaflet-pane,
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-tile-container,
|
||||
.leaflet-pane > svg,
|
||||
.leaflet-pane > canvas,
|
||||
.leaflet-zoom-box,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-layer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-container {
|
||||
overflow: hidden;
|
||||
}
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
/* Prevents IE11 from highlighting tiles in blue */
|
||||
.leaflet-tile::selection {
|
||||
background: transparent;
|
||||
}
|
||||
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
|
||||
.leaflet-safari .leaflet-tile {
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
}
|
||||
/* hack that prevents hw layers "stretching" when loading new tiles */
|
||||
.leaflet-safari .leaflet-tile-container {
|
||||
width: 1600px;
|
||||
height: 1600px;
|
||||
-webkit-transform-origin: 0 0;
|
||||
}
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
display: block;
|
||||
}
|
||||
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
|
||||
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
|
||||
.leaflet-container .leaflet-overlay-pane svg {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
}
|
||||
.leaflet-container .leaflet-marker-pane img,
|
||||
.leaflet-container .leaflet-shadow-pane img,
|
||||
.leaflet-container .leaflet-tile-pane img,
|
||||
.leaflet-container img.leaflet-image-layer,
|
||||
.leaflet-container .leaflet-tile {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
width: auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.leaflet-container img.leaflet-tile {
|
||||
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
|
||||
mix-blend-mode: plus-lighter;
|
||||
}
|
||||
|
||||
.leaflet-container.leaflet-touch-zoom {
|
||||
-ms-touch-action: pan-x pan-y;
|
||||
touch-action: pan-x pan-y;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag {
|
||||
-ms-touch-action: pinch-zoom;
|
||||
/* Fallback for FF which doesn't support pinch-zoom */
|
||||
touch-action: none;
|
||||
touch-action: pinch-zoom;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.leaflet-container {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.leaflet-container a {
|
||||
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
|
||||
}
|
||||
.leaflet-tile {
|
||||
filter: inherit;
|
||||
visibility: hidden;
|
||||
}
|
||||
.leaflet-tile-loaded {
|
||||
visibility: inherit;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
width: 0;
|
||||
height: 0;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
z-index: 800;
|
||||
}
|
||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
||||
.leaflet-overlay-pane svg {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.leaflet-pane { z-index: 400; }
|
||||
|
||||
.leaflet-tile-pane { z-index: 200; }
|
||||
.leaflet-overlay-pane { z-index: 400; }
|
||||
.leaflet-shadow-pane { z-index: 500; }
|
||||
.leaflet-marker-pane { z-index: 600; }
|
||||
.leaflet-tooltip-pane { z-index: 650; }
|
||||
.leaflet-popup-pane { z-index: 700; }
|
||||
|
||||
.leaflet-map-pane canvas { z-index: 100; }
|
||||
.leaflet-map-pane svg { z-index: 200; }
|
||||
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
.lvml {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
/* control positioning */
|
||||
|
||||
.leaflet-control {
|
||||
position: relative;
|
||||
z-index: 800;
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-top,
|
||||
.leaflet-bottom {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-top {
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-right {
|
||||
right: 0;
|
||||
}
|
||||
.leaflet-bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
.leaflet-left {
|
||||
left: 0;
|
||||
}
|
||||
.leaflet-control {
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
float: right;
|
||||
}
|
||||
.leaflet-top .leaflet-control {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.leaflet-left .leaflet-control {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom and fade animations */
|
||||
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
-moz-transition: opacity 0.2s linear;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity: 1;
|
||||
}
|
||||
.leaflet-zoom-animated {
|
||||
-webkit-transform-origin: 0 0;
|
||||
-ms-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
svg.leaflet-zoom-animated {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-tile,
|
||||
.leaflet-pan-anim .leaflet-tile {
|
||||
-webkit-transition: none;
|
||||
-moz-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* cursors */
|
||||
|
||||
.leaflet-interactive {
|
||||
cursor: pointer;
|
||||
}
|
||||
.leaflet-grab {
|
||||
cursor: -webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
cursor: grab;
|
||||
}
|
||||
.leaflet-crosshair,
|
||||
.leaflet-crosshair .leaflet-interactive {
|
||||
cursor: crosshair;
|
||||
}
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-control {
|
||||
cursor: auto;
|
||||
}
|
||||
.leaflet-dragging .leaflet-grab,
|
||||
.leaflet-dragging .leaflet-grab .leaflet-interactive,
|
||||
.leaflet-dragging .leaflet-marker-draggable {
|
||||
cursor: move;
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
/* marker & overlays interactivity */
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-pane > svg path,
|
||||
.leaflet-tile-container {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.leaflet-interactive,
|
||||
.leaflet-image-layer.leaflet-interactive,
|
||||
.leaflet-pane > svg path.leaflet-interactive,
|
||||
svg.leaflet-image-layer.leaflet-interactive path {
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* visual tweaks */
|
||||
|
||||
.leaflet-container {
|
||||
background: #ddd;
|
||||
outline-offset: 1px;
|
||||
}
|
||||
.leaflet-container a {
|
||||
color: #0078A8;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
border: 2px dotted #38f;
|
||||
background: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
||||
/* general toolbar styles */
|
||||
|
||||
.leaflet-bar {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-control-layers-toggle {
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
}
|
||||
.leaflet-bar a:hover,
|
||||
.leaflet-bar a:focus {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.leaflet-bar a:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.leaflet-bar a.leaflet-disabled {
|
||||
cursor: default;
|
||||
background-color: #f4f4f4;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-bar a {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:first-child {
|
||||
border-top-left-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
|
||||
/* zoom control */
|
||||
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out {
|
||||
font: bold 18px 'Lucida Console', Monaco, monospace;
|
||||
text-indent: 1px;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
|
||||
/* layers control */
|
||||
|
||||
.leaflet-control-layers {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers.png);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.leaflet-retina .leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers-2x.png);
|
||||
background-size: 26px 26px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers-toggle {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
.leaflet-control-layers .leaflet-control-layers-list,
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
|
||||
display: none;
|
||||
}
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-list {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
.leaflet-control-layers-expanded {
|
||||
padding: 6px 10px 6px 6px;
|
||||
color: #333;
|
||||
background: #fff;
|
||||
}
|
||||
.leaflet-control-layers-scrollbar {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.leaflet-control-layers-selector {
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
.leaflet-control-layers label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
font-size: 1.08333em;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 5px -10px 5px -6px;
|
||||
}
|
||||
|
||||
/* Default icon URLs */
|
||||
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
|
||||
background-image: url(images/marker-icon.png);
|
||||
}
|
||||
|
||||
|
||||
/* attribution and scale controls */
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
margin: 0;
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.leaflet-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover,
|
||||
.leaflet-control-attribution a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.leaflet-attribution-flag {
|
||||
display: inline !important;
|
||||
vertical-align: baseline !important;
|
||||
width: 1em;
|
||||
height: 0.6669em;
|
||||
}
|
||||
.leaflet-left .leaflet-control-scale {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control-scale {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.leaflet-control-scale-line {
|
||||
border: 2px solid #777;
|
||||
border-top: none;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
white-space: nowrap;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
text-shadow: 1px 1px #fff;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top: 2px solid #777;
|
||||
border-bottom: none;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
|
||||
border-bottom: 2px solid #777;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-attribution,
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
|
||||
/* popup */
|
||||
|
||||
.leaflet-popup {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding: 1px;
|
||||
text-align: left;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
margin: 13px 24px 13px 20px;
|
||||
line-height: 1.3;
|
||||
font-size: 13px;
|
||||
font-size: 1.08333em;
|
||||
min-height: 1px;
|
||||
}
|
||||
.leaflet-popup-content p {
|
||||
margin: 17px 0;
|
||||
margin: 1.3em 0;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-top: -1px;
|
||||
margin-left: -20px;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-popup-tip {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
padding: 1px;
|
||||
|
||||
margin: -10px auto 0;
|
||||
pointer-events: auto;
|
||||
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.leaflet-popup-content-wrapper,
|
||||
.leaflet-popup-tip {
|
||||
background: white;
|
||||
color: #333;
|
||||
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
border: none;
|
||||
text-align: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font: 16px/24px Tahoma, Verdana, sans-serif;
|
||||
color: #757575;
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button:hover,
|
||||
.leaflet-container a.leaflet-popup-close-button:focus {
|
||||
color: #585858;
|
||||
}
|
||||
.leaflet-popup-scrolled {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper {
|
||||
-ms-zoom: 1;
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
width: 24px;
|
||||
margin: 0 auto;
|
||||
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-control-zoom,
|
||||
.leaflet-oldie .leaflet-control-layers,
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper,
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
|
||||
/* div icon */
|
||||
|
||||
.leaflet-div-icon {
|
||||
background: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
|
||||
|
||||
/* Tooltip */
|
||||
/* Base styles for the element that has a tooltip */
|
||||
.leaflet-tooltip {
|
||||
position: absolute;
|
||||
padding: 6px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 3px;
|
||||
color: #222;
|
||||
white-space: nowrap;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-tooltip.leaflet-interactive {
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-tooltip-top:before,
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border: 6px solid transparent;
|
||||
background: transparent;
|
||||
content: "";
|
||||
}
|
||||
|
||||
/* Directions */
|
||||
|
||||
.leaflet-tooltip-bottom {
|
||||
margin-top: 6px;
|
||||
}
|
||||
.leaflet-tooltip-top {
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-top:before {
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-top:before {
|
||||
bottom: 0;
|
||||
margin-bottom: -12px;
|
||||
border-top-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before {
|
||||
top: 0;
|
||||
margin-top: -12px;
|
||||
margin-left: -6px;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-left {
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-right {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
top: 50%;
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before {
|
||||
right: 0;
|
||||
margin-right: -12px;
|
||||
border-left-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-right:before {
|
||||
left: 0;
|
||||
margin-left: -12px;
|
||||
border-right-color: #fff;
|
||||
}
|
||||
|
||||
/* Printing */
|
||||
|
||||
@media print {
|
||||
/* Prevent printers from removing background-images of controls. */
|
||||
.leaflet-control {
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
}
|
||||
6
static/leaflet/leaflet.js
Normal file
6
static/leaflet/leaflet.js
Normal file
File diff suppressed because one or more lines are too long
1
static/leaflet/leaflet.js.map
Normal file
1
static/leaflet/leaflet.js.map
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue