nakarte

Source code of https://map.sikmir.ru (fork)
git clone git://git.sikmir.ru/nakarte
Log | Files | Refs | LICENSE

index.js (5950B)


      1 import L from 'leaflet';
      2 import ko from 'knockout';
      3 import './coordinates.css';
      4 import copyToClipboard from '~/lib/clipboardCopy';
      5 import Contextmenu from '~/lib/contextmenu';
      6 import {makeButtonWithBar} from '~/lib/leaflet.control.commons';
      7 import safeLocalStorage from '~/lib/safe-localstorage';
      8 import '~/lib/controls-styles/controls-styles.css';
      9 import * as formats from './formats';
     10 
     11 const DEFAULT_FORMAT = formats.DEGREES;
     12 const UNKNOWN_COORDINATES = {
     13     lat: '-------',
     14     lng: '-------'
     15 };
     16 
     17 L.Control.Coordinates = L.Control.extend({
     18         options: {
     19             position: 'bottomleft'
     20         },
     21 
     22         formats: [
     23             formats.SIGNED_DEGREES,
     24             formats.DEGREES,
     25             formats.DEGREES_AND_MINUTES,
     26             formats.DEGREES_AND_MINUTES_AND_SECONDS
     27         ],
     28 
     29         initialize: function(options) {
     30             L.Control.prototype.initialize.call(this, options);
     31 
     32             this.latlng = ko.observable();
     33             this.format = ko.observable(DEFAULT_FORMAT);
     34             this.formatCode = ko.pureComputed({
     35                 read: () => this.format().code,
     36                 write: (value) => {
     37                     for (let format of this.formats) {
     38                         if (value === format.code) {
     39                             this.format(format);
     40                             break;
     41                         }
     42                     }
     43                 }
     44             });
     45 
     46             this.formattedCoordinates = ko.pureComputed(() => {
     47                 if (this.latlng()) {
     48                     return formats.formatLatLng(this.latlng().wrap(), this.format());
     49                 }
     50                 return UNKNOWN_COORDINATES;
     51             }, this);
     52 
     53             this.wrapperClass = ko.pureComputed(() => this.format().wrapperClass, this);
     54 
     55             this.formatCode.subscribe(this.saveStateToStorage, this);
     56         },
     57 
     58         onAdd: function(map) {
     59             const {container, link, barContainer} = makeButtonWithBar(
     60                 'leaflet-contol-coordinates',
     61                 'Show coordinates at cursor',
     62                 'icon-coordinates'
     63             );
     64 
     65             this._map = map;
     66             this._container = container;
     67             this._link = link;
     68 
     69             barContainer.innerHTML = `
     70                 <div data-bind="css: wrapperClass">
     71                     <div class="leaflet-coordinates-container" data-bind="with: formattedCoordinates()">
     72                         <span class="leaflet-coordinates-latitude" data-bind="html: lat"></span>
     73                         <span class="leaflet-coordinates-longitude" data-bind="html: lng"></span>
     74                     </div>
     75                     <hr class="leaflet-coordinates-divider" />
     76                     <div data-bind="foreach: formats">
     77                         <div>
     78                             <label title="">
     79                                 <input type="radio" data-bind="checked: $parent.formatCode, value: code" 
     80                                        class="leaflet-coordinates-format-radio"/>
     81                                 <span data-bind="html: label"></span>
     82                             </label>
     83                         </div>
     84                     </div>
     85                 </div>
     86             `;
     87 
     88             barContainer.title = "Right click on map to copy coordinates";
     89 
     90             this.loadStateFromStorage();
     91             ko.applyBindings(this, container);
     92             L.DomEvent.on(link, 'click', this.onClick, this);
     93 
     94             return container;
     95         },
     96 
     97         onRemove: function() {
     98             L.DomEvent.off(this._link, 'click', this.onClick, this);
     99         },
    100 
    101         loadStateFromStorage: function() {
    102             const active = safeLocalStorage.leafletCoordinatesActive === '1';
    103             const code = safeLocalStorage.leafletCoordinatesFmt || DEFAULT_FORMAT.code;
    104 
    105             this.formatCode(code);
    106             this.setEnabled(active);
    107         },
    108 
    109         saveStateToStorage: function() {
    110             safeLocalStorage.leafletCoordinatesActive = this.isEnabled() ? '1' : '0';
    111             safeLocalStorage.leafletCoordinatesFmt = this.formatCode();
    112         },
    113 
    114         onMouseMove: function(e) {
    115             this.latlng(e.latlng);
    116         },
    117 
    118         setEnabled: function(enabled) {
    119             if (Boolean(enabled) === this.isEnabled()) {
    120                 return;
    121             }
    122             const classFunc = enabled ? 'addClass' : 'removeClass';
    123             const eventFunc = enabled ? 'on' : 'off';
    124             L.DomUtil[classFunc](this._container, 'active');
    125             L.DomUtil[classFunc](this._container, 'highlight');
    126             L.DomUtil[classFunc](this._map._container, 'coordinates-control-active');
    127             this._map[eventFunc]('mousemove', this.onMouseMove, this);
    128             this._map[eventFunc]('contextmenu', this.onMapRightClick, this);
    129             this._isEnabled = Boolean(enabled);
    130             this.latlng(null);
    131         },
    132 
    133         onMapRightClick: function(e) {
    134             L.DomEvent.stop(e);
    135 
    136             function createItem(format, options = {}) {
    137                 const {lat, lng} = formats.formatLatLng(e.latlng.wrap(), format);
    138                 const coordinates = `${lat} ${lng}`;
    139 
    140                 return {text: `${coordinates} <span class="leaflet-coordinates-menu-fmt">${format.label}</span>`,
    141                     callback: () => copyToClipboard(coordinates, e.originalEvent),
    142                     ...options};
    143             }
    144 
    145             const header = createItem(this.format(), {
    146                 text: '<b>Copy coordinates to clipboard</b>',
    147                 header: true,
    148             });
    149             const items = this.formats.map((format) => createItem(format));
    150             items.unshift(header, '-');
    151 
    152             new Contextmenu(items).show(e);
    153         },
    154 
    155         isEnabled: function() {
    156             return Boolean(this._isEnabled);
    157         },
    158 
    159         onClick: function() {
    160             this.setEnabled(!this.isEnabled());
    161             this.saveStateToStorage();
    162         }
    163     }
    164 );