import React from "react";
import { SimpleHereMap } from './SimpleHereMap';
import * as mapsjs from 'react-bootstrap';
import { fetchMonitoredArea } from '../../restmodules/MonitoredAreaRestModule';
import ReactDOMServer from 'react-dom/server';
import MonitoredAreaMarkerPopUp from './MonitoredAreaMarkerPopUp';
import { withNamespaces } from 'react-i18next';
/**
* Map of zones
* @extends Component
* @hideconstructor
*/
class ZonesMap extends React.Component {
/**
* @constructs
* @param props
*/
constructor(props) {
super(props);
/* Initialize React ref to map */
this.hereMap = React.createRef();
this.isDragged = false;
this.state = {
newZone: [],
monitoredArea: null
};
this.newZonePolygon = null;
this.oldZonePolygons = [];
this.clearNewZone = this.clearNewZone.bind(this);
}
/**
*
*/
clearNewZone() {
if (this.newZonePolygon && this.newZonePolygon !== null && this.newZonePolygon !== undefined) this.hereMap.current.removeObjectFromMap(this.newZonePolygon);
if (this.state.newZone !== undefined || this.state.newZone !== null || this.state.newZone.length !== 0) this.hereMap.current.removeObjectsFromMap(this.state.newZone);
this.newZonePolygon = null;
this.setState({
newZone: []
}, this.saveChanges
);
}
/**
*
*/
saveChanges(){
let markers = this.state.newZone;
let worldVertices = {"points": [] };
for (let i = 0; i < markers.length; ++i) {
let point = markers[i].getPosition();
let vertex = {
"x": point.lat,
"y": point.lng
}
worldVertices.points.push(vertex);
}
this.props.onNewZoneMapChange(worldVertices);
}
/**
*
* @param event
*/
onMapClick = (event) => {
if (this.isDragged) {
this.isDragged = false;
return;
}
let coords = this.hereMap.current.screenToGeo(event.currentPointer.viewportX, event.currentPointer.viewportY);
let marker = new window.H.map.Marker(coords);
marker.draggable = true;
this.hereMap.current.addObjectToMap(marker);
//add this point to newZone polygon points
let points = this.state.newZone;
points.push(marker);
this.setState({
newZone: points
}, this.saveChanges
);
};
/**
*
* @param event
*/
onDragStart = (event) => {
this.isDragged = true;
let target = event.target;
if(target instanceof window.H.map.Marker){
this.hereMap.current.disableBehaviour();
}
};
/**
*
* @param event
*/
onDragEnd = (event) => {
let target = event.target;
if (target instanceof window.H.map.Marker) {
this.hereMap.current.enableBehaviour();
this.saveChanges();
this.updateMap();
}
};
/**
*
* @param event
*/
onDrag = (event) => {
this.isDragged = true;
let target = event.target,
pointer = event.currentPointer;
if (target instanceof window.H.map.Marker) {
target.setPosition(this.hereMap.current.screenToGeo(pointer.viewportX, pointer.viewportY));
}
};
/**
*
*/
updateMap(){
//draw existing zones
if (this.oldZonePolygons.length > 0) this.hereMap.current.removeObjectsFromMap(this.oldZonePolygons);
this.oldZonePolygons = [];
if (this.props.zones.length > 0) {
this.props.zones.map(zone => {
if (zone.worldVertices === undefined || zone.worldVertices === null || zone.worldVertices.points.length === 0) return;
let coords = zone.worldVertices.points;
let lineString = new window.H.geo.LineString();
for (let i = 0; i < coords.length; ++i) {
//add a point from worldVertices.points, ie. a polygon vertice, to lineString
//x is lat, y is lng, altitude is set to 100
lineString.pushLatLngAlt(coords[i].x, coords[i].y, 100);
}
//lineString.pushLatLngAlt(coords[0].x, coords[0].y, 100);
//create polygon from the linestring
let polygon = new window.H.map.Polygon(lineString, {
style: {
fillColor: 'rgba(255, 152, 56, 0.5)',
strokeColor: '#ff8614',
lineWidth: 3
}
});
//and add the object to HereMap
this.oldZonePolygons.push(polygon);
this.hereMap.current.addObjectToMap(polygon);
//draw names as markers if need be
if (this.props.showZoneNames === undefined || this.props.showZoneNames === true) {
let svgMarkup = '<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">' +
'<text x="10" y="18" font-size="12pt" font-family="Arial" font-weight="bold" ' +
'text-anchor="middle" fill="white">${TEXT}</text></svg>';
let zoneIcon = new window.H.map.Icon(
svgMarkup.replace('${TEXT}', zone.zoneNumber.toString())),
zoneMarker = new window.H.map.Marker(polygon.getBounds().getCenter(),
{icon: zoneIcon});
this.hereMap.current.addObjectToMap(zoneMarker);
this.oldZonePolygons.push(zoneMarker);
}
});
}
//remove old polygon if there is any
if (this.newZonePolygon && this.newZonePolygon !== null && this.newZonePolygon !== undefined) this.hereMap.current.removeObjectFromMap(this.newZonePolygon);
//draw new zone polygon
if (this.state.newZone === undefined || this.state.newZone === null || this.state.newZone.length === 0) return;
//get the markers from newZone
let markers = this.state.newZone;
//update worldVertices
let worldVertices = {"points": [] };
let lineString = new window.H.geo.LineString();
for (let i = 0; i < markers.length; ++i) {
//add a point from worldVertices.points, ie. a polygon vertice, to lineString
//get position from marker
let point = markers[i].getPosition();
lineString.pushLatLngAlt(point.lat, point.lng, point.alt);
let vertex = {
"x": point.lat,
"y": point.lng
}
worldVertices.points.push(vertex);
}
//create polygon from the linestring
this.newZonePolygon = new window.H.map.Polygon(lineString, {
style: {
fillColor: 'rgba(0, 255, 0, 0.5)',
strokeColor: '#00ff00',
lineWidth: 3
}
});
this.hereMap.current.addObjectToMap(this.newZonePolygon);
}
/**
*
*/
componentDidMount() {
this.updateMap();
fetchMonitoredArea(this.props.monitoredAreaID)
.then(data => this.setState({ monitoredArea: data },
this.addMonitoredAreaMarker))
.catch(error => this.setState({ monitoredArea: [{ name: error.toString() }] }));
if (this.props.interactive !== undefined && this.props.interactive === false) return;
this.hereMap.current.addEventListenerToMap('pointerup', this.onMapClick);
this.hereMap.current.addEventListenerToMap('dragstart', this.onDragStart);
this.hereMap.current.addEventListenerToMap('dragend', this.onDragEnd);
this.hereMap.current.addEventListenerToMap('drag', this.onDrag);
}
/**
*
*/
addMonitoredAreaMarker = () => {
let marker = new window.H.map.Marker({
lat: this.state.monitoredArea.deviceLatitude,
lng: this.state.monitoredArea.deviceLongitude
});
// add custom data to the marker
marker.setData(this.state.monitoredArea);
this.hereMap.current.addObjectToMap(marker);
marker.addEventListener('tap', this.handleEvent);
};
/**
*
* @param evt
*/
handleEvent = (evt) => {
if (this.props.interactive !== undefined && this.props.interactive === true) return;
// event target is the marker itself, group is a parent event target
// for all objects that it contains
let bubble = new window.H.ui.InfoBubble(evt.target.getPosition(), {
// read custom data
content: ReactDOMServer.renderToStaticMarkup(<MonitoredAreaMarkerPopUp
name={evt.target.getData().name}
id={evt.target.getData().id}
/>)
});
// show info bubble
this.hereMap.current.addBubbleToUi(bubble);
};
/**
*
*/
componentWillUnmount() {
if (this.props.interactive !== undefined && this.props.interactive === false) return;
this.hereMap.current.removeEventListenerFromMap('pointerup', this.onMapClick);
this.hereMap.current.removeEventListenerFromMap('dragstart', this.onDragStart);
this.hereMap.current.removeEventListenerFromMap('dragend', this.onDragEnd);
this.hereMap.current.removeEventListenerFromMap('drag', this.onDrag);
}
/**
*
* @param prevProps
* @param prevState
* @param snapshot
*/
componentDidUpdate(prevProps, prevState, snapshot){
this.updateMap();
}
/**
*
* @returns {*}
*/
render() {
const { t } = this.props;
let map = null;
if (this.state.monitoredArea === undefined || this.state.monitoredArea === null) {
map = <SimpleHereMap width="100%" height="400px" ref={this.hereMap}
/>
}else{
map = <SimpleHereMap width="100%" height="400px" ref={this.hereMap}
lat = { Number(this.state.monitoredArea.deviceLatitude)}
lng={Number(this.state.monitoredArea.deviceLongitude)}
zoom={19}
/>
}
return (
<div>
<div className="box-body">
{map}
</div>
<div className="box-footer no-border">
<label className="control-label fa fa-info-circle info-icon pull-right"
data-toggle="tooltip"
title={t('forms.tooltip.map')}/>
{
(this.props.interactive === undefined || this.props.interactive === true) ?
<button
style={{padding: '6px 50px'}}
type="submit"
className="btn btn-primary pull-left"
onClick={this.clearNewZone}
>{t('forms.erase')}</button>
: null
}
</div>
</div>
)
}
}
export default withNamespaces()(ZonesMap);