src/controls/SingleDrawButton.js
import $ from 'jquery'
import { Feature } from 'ol'
import LineString from 'ol/geom/LineString'
import { getLength } from 'ol/sphere'
import { Control } from './Control'
import { cssClasses, keyCodes } from '../globals'
import { VectorLayer } from '../layers/VectorLayer'
import '../../less/singledrawbutton.less'
import { mixin } from '../utilities'
import { Dropdown } from '../html/Dropdown'
import { ActivatableMixin } from './ActivatableMixin'
import Draw from 'ol/interaction/Draw'
import VectorSource from 'ol/source/Vector'
/**
* @typedef {g4uControlOptions} DrawButtonsOptions
* @property {StyleLike} [editStyle='#defaultStyle']
* @property {StyleLike} [finishedStyle='#defaultStyle']
*/
/**
* Enables the user to draw, edit and erase geometries on the map
*/
export class SingleDrawButton extends mixin(Control, ActivatableMixin) {
/**
* @param {DrawButtonsOptions} options
*/
constructor (options = {}) {
options.element = $('<div>').get(0)
options.className = options.className || 'g4u-single-draw'
options.singleButton = false
super(options)
/**
* @type {StyleLike}
* @private
*/
this.editStyle_ = options.editStyle || '#defaultStyle'
/**
* @type {StyleLike}
* @private
*/
this.finishedStyle_ = options.finishedStyle || '#defaultStyle'
this.setTitle(this.getTitle() ||
this.getLocaliser().localiseUsingDictionary('SingleDrawButton title')
)
this.setTipLabel(this.getTipLabel() ||
this.getLocaliser().localiseUsingDictionary('SingleDrawButton tipLabel')
)
this.createHTML()
}
createHTML () {
const $button = $('<button>')
.addClass(this.getClassName() + '-button')
.addClass(cssClasses.mainButton)
.text(this.getTitle())
.on('click', () => {
if (this.getActive()) {
this.setActive(false)
} else {
this.dropdown_.slideDown()
}
})
this.get$Element().append($button)
this.dropdown_ = new Dropdown()
this.dropdown_.setEntries([
'Point',
'LineString',
'Polygon',
'Circle',
'Delete'
], [
this.getLocaliser().localiseUsingDictionary('SingleDrawButton draw point'),
this.getLocaliser().localiseUsingDictionary('SingleDrawButton draw line'),
this.getLocaliser().localiseUsingDictionary('SingleDrawButton draw polygon'),
this.getLocaliser().localiseUsingDictionary('SingleDrawButton draw circle'),
this.getLocaliser().localiseUsingDictionary('SingleDrawButton delete all')
])
this.dropdown_.on('select', () => {
const mode = this.dropdown_.getValue()
if (mode === 'Delete') {
this.layer_.getSource().clear()
} else {
this.setActive(true)
}
})
this.get$Element().append(this.dropdown_.get$Element())
}
setActive (active) {
if (active) {
const mode = this.dropdown_.getValue()
this.addInteraction(mode)
this.dropdown_.slideUp()
} else if (this.interaction_) {
this.removeInteraction()
}
super.setActive(active)
this.get$Element().toggleClass(cssClasses.active, active)
}
addInteraction (mode) {
const map = this.getMap()
const style = map.get('styling').getStyle(this.editStyle_)
this.interaction_ = new Draw({
source: this.layer_.getSource(),
type: mode,
style: style
})
$(map.getViewport()).addClass(cssClasses.crosshair)
map.addSupersedingInteraction('singleclick dblclick pointermove', this.interaction_)
this.interaction_.on('drawend', () => {
this.setActive(false)
})
}
removeInteraction () {
const map = this.getMap()
this.interaction_.setActive(false)
map.removeInteraction(this.interaction_)
this.interaction_ = undefined
$(map.getViewport()).removeClass(cssClasses.crosshair)
}
/**
* @param {G4UMap} map
*/
setMap (map) {
if (this.getMap()) {
this.getMap().getLayers().remove(this.layer_)
if (this.interaction_) {
this.removeInteraction()
}
}
super.setMap(map)
if (map) {
/**
* @type {VectorLayer}
* @private
*/
this.layer_ = new VectorLayer({
source: new VectorSource(),
visible: true
})
this.layer_.setStyle(map.get('styling').getStyle(this.finishedStyle_))
map.get('styling').manageLayer(this.layer_)
map.addLayer(this.layer_) // at 0 the baselayers are
$(map.getViewport()).parent().on('keydown', e => {
if (e.which === keyCodes.ESCAPE && this.interaction_) {
this.removeInteraction()
}
})
this.addMeasureLine()
}
}
getLayer () {
return this.layer_
}
addMeasureLine () {
let lastPoint = null
const style = this.getMap().get('styling').getStyle(this.editStyle_).clone()
style.setZIndex(style.getZIndex() + 1)
const projection = this.getMap().getView().getProjection()
const measureLine = new Feature()
measureLine.setStyle(() => {
if (style.getText()) {
const length = getLength(measureLine.getGeometry(), { projection })
style.getText().setText(length.toFixed(0) + ' m')
}
return style
})
this.layer_.getSource().addFeature(measureLine)
this.getMap().on('singleclick', e => {
measureLine.set('hidden', true)
lastPoint = e.coordinate
})
this.getMap().on('pointermove', e => {
if (this.getActive() && lastPoint) {
const geometry = new LineString([lastPoint, e.coordinate])
measureLine.setGeometry(geometry)
measureLine.set('hidden', false)
}
})
this.on('change:active', () => {
lastPoint = null
measureLine.set('hidden', true)
})
}
}