'use strict'; /*@ Ox.MapMarker MapMarker (options) -> MapMarker object options Options object color marker color map map place place size size @*/ Ox.MapMarker = function(options) { options = Ox.extend({ map: null, place: null }, options); var that = this, areaSize = { 100: 10, // 10 x 10 m 10000: 12, // 100 x 100 m 1000000: 14, // 1 x 1 km 100000000: 16, // 10 x 10 km 10000000000: 18, // 100 x 100 km 1000000000000: 20, // 1,000 x 1,000 km 100000000000000: 22 // 10,000 x 10,000 km }, themeData = Ox.Theme.getThemeData(), typeColor = {}; [ 'country', 'region', 'city', 'borough', 'street', 'building', 'feature' ].forEach(function(type) { typeColor[type] = themeData[ 'mapPlace' + Ox.toTitleCase(type) + 'Color' ]; }); Ox.forEach(options, function(val, key) { that[key] = val; }); setColor() setSize() const element = document.createElement('div') element.style.border = '2px solid black' element.style.borderRadius = '50px' element.style.backgroundColor = '#' + Ox.toHex(that.color) element.style.width = element.style.height = that.size + 'px' that.marker = new maplibregl.Marker({ raiseOnDrag: false, element: element, //shape: {coords: [8, 8, 8], type: 'circle'}, //title: that.place.name, //zIndex: 1000 }); that.tooltip = new maplibregl.Popup({ closeButton: false, closeOnClick: false, className: 'tooltip' }); that.tooltip.addClass setOptions(); function click(event) { event.preventDefault() event.stopPropagation() var key = that.map.getKey(), place, bounds, southWest, northEast; if (!that.place.selected) { if ( that.map.options('editable') && (key == 'meta' || key == 'shift') ) { place = that.map.getSelectedPlace(); } if (place) { bounds = new maplibregl.LngLatBounds( new maplibregl.LngLatBounds(place.west, place.south), new maplibregl.LngLatBounds(place.east, place.north) ); bounds = bounds.union(that.place.bounds); southWest = bounds.getSouthWest(); northEast = bounds.getNorthEast(); that.map.newPlace(new Ox.MapPlace({ // fixme: duplicated, see Ox.Map.js alternativeNames: [], countryCode: '', editable: true, geoname: '', id: '_' + Ox.encodeBase32(Ox.uid()), // fixme: stupid map: that.map, name: '', type: 'feature', south: southWest.lat, west: southWest.lng, north: northEast.lat, east: northEast.lng })); } else { that.map.options({selected: that.place.id}); } } else { if (key == 'meta') { that.map.options({selected: null}); } else { that.map.panToPlace(); } } } function dblclick() { that.place.selected && that.map.zoomToPlace(); } function dragstart(e) { Ox.$body.addClass('OxDragging'); } function drag(e) { var northSouth = (that.place.north - that.place.south) / 2, lat = Ox.limit( e.lngLat.lat, Ox.MIN_LATITUDE + northSouth, Ox.MAX_LATITUDE - northSouth ), lng = e.lngLat.lng, span = Math.min( that.place.sizeEastWest * Ox.getDegreesPerMeter(lat) / 2, 179.99999999 ), degreesPerMeter = Ox.getDegreesPerMeter(lat); that.place.south += lat - that.place.lat; that.place.north += lat - that.place.lat; that.place.west = lng - span; that.place.east = lng + span; if (that.place.west < -180) { that.place.west += 360; } else if (that.place.east > 180) { that.place.east -= 360; } Ox.Log('Map', 'west', that.place.west, 'east', that.place.east, 'span', span); that.place.update(); that.marker.setLngLat(that.place.center) that.place.rectangle.update(); } function dragend(e) { Ox.$body.removeClass('OxDragging'); that.map.triggerEvent('changeplaceend', that.place); } function getMarkerImage(options, callback) { // fixme: unused options = Ox.extend({ background: [255, 0, 0], editing: false, result: false, selected: false, size: 16 }, options); var background = options.result ? [255, 255, 0] : [255, 0, 0], border = options.editing ? [128, 128, 255] : options.selected ? [255, 255, 255] : [0, 0, 0], c = Ox.canvas(options.size, options.size), image, r = options.size / 2; if (Ox.isArray(background)) { c.context.fillStyle = 'rgba(' + background.join(', ') + ', 0.5)'; c.context.arc(r, r, r - 2, 0, 360); c.context.fill(); renderImage(); } else { image = new Image(); image.onload = renderImage; image.src = background; } function renderImage() { //var i; if (Ox.isString(background)) { c.context.drawImage(image, 1, 1, options.size - 2, options.size - 2); /* c.imageData = c.context.getImageData(0, 0, options.size, options.size); c.data = c.imageData.data; for (i = 3; i < c.data.length; i += 1) { c.data[i] = Math.round(c.data[i] * 0.5); } c.context.putImageData(c.imageData, 0, 0); */ } c.context.beginPath(); c.context.lineWidth = 2; c.context.strokeStyle = 'rgb(' + border.join(', ') + ')'; c.context.arc(r, r, r - 1, 0, 360); c.context.stroke(); callback(new maplibregl.MarkerImage( c.canvas.toDataURL(), new maplibregl.Size(options.size, options.size), new maplibregl.Point(0, 0), new maplibregl.Point(r, r) )); } } function mouseover(e) { that.tooltip.setLngLat(that.place.center).setHTML( '
' + '
' + that.map.options('markerTooltip')(that.place) + '
' ).addTo(that.map.map); } function mouseout() { that.tooltip.remove(); } function setColor() { var color = that.map.options('markerColor'); //Ox.Log('Map', 'setOptions, that.map: ', that.map) if (color == 'auto') { that.color = typeColor[that.place.type] || typeColor['mapPlaceFeatureColor']; } else if (Ox.isArray(color)) { that.color = color; } else { that.color = color(that.place); } } function setSize() { var size = that.map.options('markerSize'); if (size == 'auto') { that.size = 8; Ox.forEach(areaSize, function(size, area) { if (that.place.area >= area) { that.size = size; } else { return false; // break } }); } else if (Ox.isNumber(size)) { that.size = size; } else { that.size = size(that.place); } } function setOptions() { // workaround to prevent marker from appearing twice // after setting draggable from true to false (google maps bug) var fix = false, // that.marker.getDraggable() && !that.place.editing, size = that.map.options('markerSize'); //Ox.Log('Map', 'setOptions, that.map: ', that.map) setColor() setSize() /* fixme, some of those can be set some not that.marker.setOptions({ // fixme: cursor remains pointer cursor: that.place.editing ? 'move' : 'pointer', draggable: that.place.editing, element: Ox.MapMarkerImage({ color: that.color, mode: that.place.editing ? 'editing' : that.place.selected ? 'selected' : 'normal', size: that.size, type: that.place.id[0] == '_' ? 'result' : 'place' }), }) */ //that.marker._color = that.color; that.marker._element.style.cursor = that.place.editing ? 'move' : 'pointer'; that.marker._element.height = that.marker._element.width = that.size + 'px' that.marker.setDraggable(that.place.editing); that.marker.setLngLat(that.place.center); if (fix) { that.marker.setVisible(false); setTimeout(function() { that.marker.setVisible(true); }, 0); } } /*@ add add to map () -> add to map, returns MapMarker @*/ that.add = function() { that.marker.addTo(that.map.map); const element = that.marker.getElement() if(element) { element.addEventListener('click', click) element.addEventListener('dblclick', dblclick) element.addEventListener('mouseover', mouseover) element.addEventListener('mouseout', mouseout) } return that; }; /*@ edit edit marker () -> edit marker, returns MapMarker @*/ that.edit = function() { setOptions(); that.marker.on('dragstart', dragstart); that.marker.on('drag', drag); that.marker.on('dragend', dragend); return that; }; /*@ remove remove marker () -> remove marker from map, returns MapMarker @*/ that.remove = function() { that.marker.remove(); //that.marker.off('dragstart'); //that.marker.off('drag'); //that.marker.off('dragend'); //fixme does this work to remove all events? that.marker.off(); return that; }; /*@ submit submit marker () -> clear edit listeners, returns MapMarker @*/ that.submit = function() { that.marker.off('dragstart'); that.marker.off('drag'); that.marker.off('dragend'); return that; } /*@ update update marker () -> update marker, returns MapMarker @*/ that.update = function() { setOptions(); return that; } return that; };