You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
8.3 KiB
300 lines
8.3 KiB
import React, { useEffect, useRef } from 'react' |
|
import ReactDOMServer from 'react-dom/server' |
|
import { createTileLayerComponent, updateGridLayer } from '@react-leaflet/core' |
|
import L from 'leaflet' |
|
import isObject from 'lodash/isObject' |
|
import isFunction from 'lodash/isFunction' |
|
import isString from 'lodash/isString' |
|
import isEmpty from 'lodash/isEmpty' |
|
import clone from 'lodash/clone' |
|
import cloneDeep from 'lodash/cloneDeep' |
|
import extend from 'lodash/extend' |
|
import merge from 'lodash/merge' |
|
import has from 'lodash/has' |
|
import find from 'lodash/find' |
|
import 'leaflet.vectorgrid' |
|
import './L.VectorGrid.VectorPoi' |
|
import { Popup, useMap } from 'react-leaflet' |
|
import { Button, Col, Row } from 'reactstrap' |
|
const PopElement = () => { |
|
return ( |
|
<> |
|
<Row> |
|
<Col> |
|
<h3>Hallo</h3> |
|
</Col> |
|
</Row> |
|
<Row> |
|
<Col> |
|
<Button id="tombol">TEST</Button> |
|
</Col> |
|
</Row> |
|
</> |
|
) |
|
} |
|
|
|
export const VectorGridd = createTileLayerComponent( |
|
function createTileLayer(props, context) { |
|
const highlight = useRef(null) |
|
const active = useRef(null) |
|
const map = useMap() |
|
const { |
|
data, |
|
style, |
|
hoverStyle, |
|
activeStyle, |
|
onPopupOpen, |
|
onClick, |
|
onMouseover, |
|
onMouseout, |
|
onDblclick, |
|
onContextmenu, |
|
vectorTileLayerStyles, |
|
url, |
|
maxNativeZoom, |
|
subdomains, |
|
accessKey, |
|
accessToken, |
|
type = 'protobuf', |
|
interactive = true, |
|
idField = '', |
|
...rest |
|
} = props |
|
delete rest.leaflet |
|
|
|
useEffect(() => { |
|
console.log({ vectorGrid }) |
|
const { tooltipClassName = '', tooltip = null, popup = null } = props |
|
if (tooltip) { |
|
vectorGrid.bindTooltip( |
|
(layer) => { |
|
if (isFunction(tooltip)) { |
|
return tooltip(layer) |
|
} else if (isString(tooltip) && has(layer.properties, tooltip)) { |
|
return String(layer.properties[tooltip]) |
|
} else if (isString(tooltip)) { |
|
return tooltip |
|
} |
|
return '' |
|
}, |
|
{ |
|
sticky: true, |
|
direction: 'auto', |
|
className: tooltipClassName |
|
} |
|
) |
|
// vectorGrid.bindTooltip( |
|
// (layer) => { |
|
// const id = _getFeatureId(layer) |
|
// return id |
|
// }, |
|
// { |
|
// sticky: true, |
|
// direction: 'auto', |
|
// className: tooltipClassName |
|
// } |
|
// ) |
|
} |
|
if (popup) { |
|
// console.log({ vectorGrid }) |
|
// vectorGrid.bindPopup(popup) |
|
// vectorGrid.bindPopup((layer) => { |
|
// // console.log({ a, b }) |
|
// if (isFunction(popup)) { |
|
// return popup(layer) |
|
// } else if (isString(toopopupltip) && has(layer.properties, popup)) { |
|
// return String(layer.properties[popup]) |
|
// } else if (isString(popup)) { |
|
// return popup |
|
// } |
|
// return '' |
|
// }) |
|
} |
|
}, [props.tooltip, props.popup]) |
|
|
|
const baseStyle = (properties, zoom) => { |
|
if (isFunction(style)) { |
|
return style(properties) |
|
} else if (isObject(style)) { |
|
return style |
|
} |
|
return { |
|
weight: 0.5, |
|
opacity: 1, |
|
color: '#ccc', |
|
fillColor: '#390870', |
|
fillOpacity: 0.6, |
|
fill: true, |
|
stroke: true |
|
} |
|
} |
|
|
|
const _getFeatureId = (feature) => { |
|
const { idField } = props |
|
if (isFunction(idField)) { |
|
return idField(feature) |
|
} else if (isString(idField)) { |
|
// console.log(feature.properties[idField]) |
|
return feature.properties[idField] |
|
} |
|
} |
|
|
|
const setFeatureStyle = (id, style) => { |
|
vectorGrid.setFeatureStyle(id, style) |
|
} |
|
|
|
const resetFeatureStyle = (id) => { |
|
vectorGrid.resetFeatureStyle(id) |
|
} |
|
|
|
const clearHighlight = (properties) => { |
|
if (highlight.current) { |
|
if (highlight.current !== active.current) { |
|
resetFeatureStyle(highlight.current) |
|
} else { |
|
let st |
|
if (isFunction(activeStyle)) { |
|
st = activeStyle(properties) |
|
} else if (isObject(activeStyle)) { |
|
st = cloneDeep(activeStyle) |
|
} |
|
if (!isEmpty(st)) { |
|
const base = cloneDeep(baseStyle(properties)) |
|
const activeStyle = extend(base, st) |
|
setFeatureStyle(active.current, activeStyle) |
|
} |
|
} |
|
} |
|
highlight.current = null |
|
} |
|
|
|
const clearActive = () => { |
|
if (active.current) { |
|
resetFeatureStyle(active.current) |
|
} |
|
active.current = null |
|
} |
|
|
|
const getFeature = (featureId) => { |
|
const { data, idField } = props |
|
if (isEmpty(data) || isEmpty(data.features)) return {} |
|
const feature = find(data.features, ({ properties }) => properties[idField] === featureId) |
|
return cloneDeep(feature) |
|
} |
|
|
|
const _propagateEvent = (eventHandler, e) => { |
|
if (!isFunction(eventHandler)) return |
|
const featureId = _getFeatureId(e.layer) |
|
const feature = getFeature(featureId) |
|
const event = cloneDeep(e) |
|
const mergedEvent = merge(event.target, { |
|
feature |
|
}) |
|
eventHandler(event) |
|
} |
|
|
|
let vectorGrid |
|
if (type === 'slicer') { |
|
vectorGrid = new L.vectorGrid.slicer(data, { |
|
interactive: interactive, |
|
getFeatureId: (feature) => _getFeatureId(feature), |
|
rendererFactory: L.svg.tile, |
|
vectorTileLayerStyles: vectorTileLayerStyles || { |
|
sliced: (properties, zoom) => { |
|
const bs = baseStyle(properties, zoom) |
|
bs.fill = true |
|
bs.stroke = true |
|
return bs |
|
} |
|
}, |
|
...rest |
|
}) |
|
} else { |
|
vectorGrid = new L.vectorGrid.vectorpoi(url, { |
|
interactive: interactive, |
|
key: accessKey, |
|
token: accessToken, |
|
vectorTileLayerStyles: vectorTileLayerStyles, |
|
getFeatureId: (feature) => _getFeatureId(feature), |
|
rendererFactory: L.svg.tile, |
|
...rest |
|
}) |
|
} |
|
|
|
vectorGrid |
|
.on('mouseover', (e) => { |
|
const { properties } = e.layer |
|
_propagateEvent(onMouseover, e) |
|
let st |
|
const featureId = _getFeatureId(e.layer) |
|
if (isFunction(hoverStyle)) { |
|
st = hoverStyle(properties) |
|
} else if (isObject(hoverStyle)) { |
|
st = cloneDeep(hoverStyle) |
|
} |
|
if (!isEmpty(st) && featureId) { |
|
clearHighlight(properties) |
|
highlight.current = featureId |
|
const base = cloneDeep(baseStyle(properties)) |
|
const hoverStyle = extend(base, st) |
|
setFeatureStyle(featureId, hoverStyle) |
|
} |
|
}) |
|
.on('mouseout', (e) => { |
|
const { properties } = e.layer |
|
_propagateEvent(onMouseout, e) |
|
clearHighlight(properties) |
|
}) |
|
.on('click', (e) => { |
|
const { properties } = e.layer |
|
const lat_lng = new L.LatLng(properties.GEO_LOK_LAT, properties.GEO_LOK_LING) |
|
|
|
// (Number(properties.GEO_LOK_LING), Number(properties.GEO_LOK_LAT)) |
|
const featureId = _getFeatureId(e.layer) |
|
// console.log({ properties, featureId }) |
|
// console.log(e.layer) |
|
// console.log(properties) |
|
_propagateEvent(onClick, e) |
|
let st |
|
if (isFunction(activeStyle)) { |
|
st = activeStyle(properties) |
|
} else if (isObject(activeStyle)) { |
|
st = cloneDeep(activeStyle) |
|
} |
|
if (!isEmpty(st) && featureId) { |
|
clearActive() |
|
active.current = featureId |
|
const base = cloneDeep(baseStyle(properties)) |
|
const activeStyle = extend(base, st) |
|
setFeatureStyle(featureId, activeStyle) |
|
} |
|
//json get Detail |
|
L.popup() |
|
.setLatLng(lat_lng) |
|
.setContent(ReactDOMServer.renderToString(<PopElement />)) |
|
// .setContent(useRenderPopup({})) |
|
.openOn(map) |
|
}) |
|
.on('dblclick', (e) => { |
|
_propagateEvent(onDblclick, e) |
|
clearActive() |
|
}) |
|
.on('contextmenu', (e) => { |
|
_propagateEvent(onContextmenu, e) |
|
clearActive() |
|
}) |
|
|
|
map.on('popupopen', () => { |
|
console.log('mapopenpopup') |
|
}) |
|
return { |
|
instance: vectorGrid, |
|
context |
|
} |
|
}, |
|
function upgrade(layer, props, prevprops) { |
|
return updateGridLayer(layer, props, prevprops) |
|
} |
|
) |
|
|
|
export default VectorGridd
|
|
|