import { mount, h, s } from 'lib/rx' import * as Color from 'lib/color' import * as M from 'lib/leaflet' import * as icons from 'lib/icons' import * as markerModel from 'models/marker' interface CreateParams { marker: markerModel.Marker, onMove: (marker: M.Layer) => void, onClick: (markerElem: M.FeatureGroup) => void, } export function create({ marker, onMove, onClick }: CreateParams): M.FeatureGroup { const { lat, lng, color, icon, name, description, radius } = marker const pos = { lat, lng } const markerElem = M.marker(pos, { draggable: true, autoPan: true, icon: divIcon({ icon, color, name, description }) }) const circle = radius !== undefined && radius !== 0 ? M.circle(pos, { radius, color, fillColor: color }) : undefined const layer = circle !== undefined ? M.featureGroup([ markerElem, circle ]) : M.featureGroup([ markerElem ]) markerElem.addEventListener('drag', e => { circle && circle.setLatLng(markerElem.getLatLng()) }) markerElem.addEventListener('dragend', () => onMove(markerElem)) markerElem.addEventListener('click', (e: M.MapEvent) => onClick(layer)) return layer } interface CreateIconParams { icon?: string, color: string, name?: string, description?: string } function divIcon({ icon, color, name, description }: CreateIconParams): M.Icon { const c = Color.parse(color) const crBlack = Color.contrastRatio({ red: 0, green: 0, blue: 0 }, c) const crWhite = Color.contrastRatio({ red: 255, green: 255, blue: 255 }, c) const textCol = crBlack > crWhite ? 'black' : 'white' const width = 10 const height = 15 const stroke = 'black' const strokeWidth = 0.6 // Triangle const t = [ { x: width * 0.15, y: 7.46 }, { x: width / 2, y: height }, { x: width * 0.85, y: 7.46 } ] const html = document.createElement('div') html.className = 'g-Marker' if (description) html.title = description mount(html, [ s('svg', { viewBox: `0 0 ${width} ${height}`, class: 'g-Marker__Base' }, s('circle', { cx: width / 2, cy: width / 2, r: (width - 2 * strokeWidth) / 2, stroke, 'stroke-width': strokeWidth, fill: color } ), s('polygon', { points: `${t[0].x},${t[0].y} ${t[1].x},${t[1].y} ${t[2].x},${t[2].y}`, fill: color }), s('line', { x1: t[0].x, y1: t[0].y, x2: t[1].x, y2: t[1].y, stroke, 'stroke-width': strokeWidth }), s('line', { x1: t[1].x, y1: t[1].y, x2: t[2].x, y2: t[2].y, stroke, 'stroke-width': strokeWidth }), ), icon && icons.svg(icon, { class: 'g-Marker__Icon', style: `fill: ${textCol}; stroke: ${textCol}` }), name && h('div', { className: 'g-Marker__Title', style: `text-shadow: ${textShadow('white', 1, 1)}` }, name ) ]) return M.divIcon({ className: '', popupAnchor: [ 0, -34 ], html }) } function textShadow(color: string, w: number, blurr: number): string { return [[-w, -w], [-w, 0], [-w, w], [0, -w], [0, w], [w, -w], [w, 0], [w, w]] .map(xs => `${color} ${xs[0]}px ${xs[1]}px ${blurr}px`) .join(', ') }