tchen-vuelayers
Version:
Web map Vue components with the power of OpenLayers
402 lines (345 loc) • 10.9 kB
JavaScript
/**
* VueLayers
* Web map Vue components with the power of OpenLayers
*
* @package vuelayers
* @author Vladimir Vershinin <ghettovoice@gmail.com>
* @version 0.11.1
* @license MIT
* @copyright (c) 2017-2019, Vladimir Vershinin <ghettovoice@gmail.com>
*/
import _regeneratorRuntime from '@babel/runtime-corejs2/regenerator';
import _asyncToGenerator from '@babel/runtime-corejs2/helpers/esm/asyncToGenerator';
import _Object$values from '@babel/runtime-corejs2/core-js/object/values';
import { noModifierKeys, shiftKeyOnly } from 'ol/events/condition';
import DrawInteraction from 'ol/interaction/Draw';
import { merge } from 'rxjs/_esm5/internal/observable/merge';
import { map } from 'rxjs/_esm5/internal/operators/map';
import interaction from '../mixin/interaction';
import stylesContainer from '../mixin/styles-container';
import { GEOMETRY_TYPE } from '../ol-ext/consts';
import { initFeature } from '../ol-ext/feature';
import { createStyle, defaultEditStyle } from '../ol-ext/style';
import { isCollection, isVectorSource } from '../ol-ext/util';
import observableFromOlEvent from '../rx-ext/from-ol-event';
import { hasInteraction } from '../util/assert';
import { camelCase, isFunction, mapValues, upperFirst, pick } from '../util/minilo';
import mergeDescriptors from '../util/multi-merge-descriptors';
import { makeWatchers } from '../util/vue-helpers';
import _Object$assign from '@babel/runtime-corejs2/core-js/object/assign';
var transformType = function transformType(type) {
return upperFirst(camelCase(type));
};
/**
* @vueProps
*/
var props = {
/**
* Target source or collection identifier from IdentityMap.
* @type {String}
*/
source: {
type: String,
required: true
},
/**
* The maximum distance in pixels between "down" and "up" for a "up" event to be considered a "click" event and
* actually add a point/vertex to the geometry being drawn. Default is 6 pixels. That value was chosen for the
* draw interaction to behave correctly on mouse as well as on touch devices.
* @type {number}
*/
clickTolerance: {
type: Number,
default: 6
},
/**
* Pixel distance for snapping to the drawing finish.
* @type {number}
*/
snapTolerance: {
type: Number,
default: 12
},
/**
* Drawing type ('Point', 'LineString', 'Polygon', 'MultiPoint', 'MultiLineString', 'MultiPolygon' or 'Circle').
* @type {string}
*/
type: {
type: String,
required: true,
validator: function validator(value) {
return _Object$values(GEOMETRY_TYPE).includes(transformType(value));
}
},
/**
* Stop click, singleclick, and doubleclick events from firing during drawing.
* @type {boolean}
*/
stopClick: {
type: Boolean,
default: false
},
/**
* The number of points that can be drawn before a polygon ring or line string is finished.
* @type {number|undefined}
*/
maxPoints: Number,
/**
* The number of points that must be drawn before a polygon ring or line string can be finished.
* Default is `3` for polygon rings and `2` for line strings.
* @type {number|undefined}
*/
minPoints: Number,
/**
* A function that takes an ol.MapBrowserEvent and returns a boolean to indicate whether the drawing can be finished.
* @type {function|undefined}
*/
finishCondition: Function,
/**
* Function that is called when a geometry's coordinates are updated.
* @type {function|undefined}
*/
geometryFunction: Function,
/**
* Name of the geometry attribute for newly created features.
* @type {string}
*/
geometryName: {
type: String,
default: 'geometry'
},
/**
* A function that takes an `ol.MapBrowserEvent` and returns a boolean to indicate whether that event should be handled.
* By default `ol.events.condition.noModifierKeys`, i.e. a click, adds a vertex or deactivates freehand drawing.
* @type {function|undefined}
*/
condition: {
type: Function,
default: noModifierKeys
},
/**
* Operate in freehand mode for lines, polygons, and circles. This makes the interaction always operate in
* freehand mode and takes precedence over any `freehandCondition` option.
* @type {boolean}
*/
freehand: {
type: Boolean,
default: false
},
/**
* Condition that activates freehand drawing for lines and polygons. This function takes an `ol.MapBrowserEvent` and
* returns a boolean to indicate whether that event should be handled. The default is `ol.events.condition.shiftKeyOnly`,
* meaning that the Shift key activates freehand drawing.
* @type {function|undefined}
*/
freehandCondition: {
type: Function,
default: shiftKeyOnly
},
/**
* Wrap the world horizontally on the sketch overlay.
* @type {boolean}
*/
wrapX: {
type: Boolean,
default: false
}
/**
* @vueMethods
*/
};
var methods = {
/**
* @return {Promise<Draw>}
* @protected
*/
createInteraction: function () {
var _createInteraction = _asyncToGenerator(
/*#__PURE__*/
_regeneratorRuntime.mark(function _callee() {
var sourceIdent, source, features;
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
sourceIdent = this.makeIdent(this.source);
_context.next = 3;
return this.$identityMap.get(sourceIdent, this.$options.INSTANCE_PROMISE_POOL);
case 3:
source = _context.sent;
if (isFunction(source.getFeatures)) {
features = source.getFeatures();
if (isCollection(features)) {
source = features;
}
}
return _context.abrupt("return", new DrawInteraction({
source: isVectorSource(source) ? source : undefined,
features: isCollection(source) ? source : undefined,
clickTolerance: this.clickTolerance,
snapTolerance: this.snapTolerance,
type: transformType(this.type),
stopClick: this.stopClick,
maxPoints: this.maxPoints,
minPoints: this.minPoints,
finishCondition: this.finishCondition,
style: this.createStyleFunc(),
geometryFunction: this.geometryFunction,
geometryName: this.geometryName,
condition: this.condition,
freehand: this.freehand,
freehandCondition: this.freehandCondition,
wrapX: this.wrapX
}));
case 6:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
return function createInteraction() {
return _createInteraction.apply(this, arguments);
};
}(),
/**
* @return {function(feature: Feature): Style}
* @protected
*/
getDefaultStyles: function getDefaultStyles() {
var defaultStyles = mapValues(defaultEditStyle(), function (styles) {
return styles.map(createStyle);
});
return function __selectDefaultStyleFunc(feature) {
if (feature.getGeometry()) {
return defaultStyles[feature.getGeometry().getType()];
}
};
},
/**
* @returns {Object}
* @protected
*/
getServices: function getServices() {
return mergeDescriptors(interaction.methods.getServices.call(this), stylesContainer.methods.getServices.call(this));
},
/**
* @return {Interaction|undefined}
* @protected
*/
getStyleTarget: function getStyleTarget() {
return this.$interaction;
},
/**
* @return {void}
* @protected
*/
mount: function mount() {
interaction.methods.mount.call(this);
},
/**
* @return {void}
* @protected
*/
unmount: function unmount() {
interaction.methods.unmount.call(this);
},
/**
* @param {Array<{style: Style, condition: (function|boolean|undefined)}>|function(feature: Feature): Style|Vue|undefined} styles
* @return {void}
* @protected
*/
setStyle: function setStyle(styles) {
if (styles !== this._styles) {
this._styles = styles;
this.scheduleRefresh();
}
},
/**
* @return {void}
* @protected
*/
subscribeAll: function subscribeAll() {
subscribeToInteractionChanges.call(this);
}
}; // todo other props?
var watch = makeWatchers(['source', 'type'], function () {
return function () {
this.scheduleRecreate();
};
});
/**
* @alias module:draw-interaction/interaction
* @title vl-interaction-draw
* @vueProto
*/
var script = {
name: 'vl-interaction-draw',
mixins: [interaction, stylesContainer],
props: props,
methods: methods,
watch: watch,
stubVNode: {
empty: false,
attrs: function attrs() {
return {
class: this.$options.name
};
}
}
/**
* @return {void}
* @private
*/
};
function subscribeToInteractionChanges() {
var _this = this;
hasInteraction(this);
var drawEvents = merge(observableFromOlEvent(this.$interaction, 'drawstart').pipe(map(function (evt) {
initFeature(evt.feature);
return evt;
})), observableFromOlEvent(this.$interaction, 'drawend'));
this.subscribeTo(drawEvents, function (evt) {
++_this.rev;
_this.$emit(evt.type, evt);
});
}
/* script */
var __vue_script__ = script;
/* template */
/* style */
var __vue_inject_styles__ = undefined;
/* scoped */
var __vue_scope_id__ = undefined;
/* module identifier */
var __vue_module_identifier__ = undefined;
/* functional template */
var __vue_is_functional_template__ = undefined;
/* component normalizer */
function __vue_normalize__(template, style, script$$1, scope, functional, moduleIdentifier, createInjector, createInjectorSSR) {
var component = (typeof script$$1 === 'function' ? script$$1.options : script$$1) || {}; // For security concerns, we use only base name in production mode.
component.__file = "interaction.vue";
if (!component.render) {
component.render = template.render;
component.staticRenderFns = template.staticRenderFns;
component._compiled = true;
if (functional) component.functional = true;
}
component._scopeId = scope;
return component;
}
/* style inject */
/* style inject SSR */
var Interaction = __vue_normalize__({}, __vue_inject_styles__, __vue_script__, __vue_scope_id__, __vue_is_functional_template__, __vue_module_identifier__, undefined, undefined);
function plugin(Vue) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (plugin.installed) {
return;
}
plugin.installed = true;
options = pick(options, 'dataProjection');
_Object$assign(Interaction, options);
Vue.component(Interaction.name, Interaction);
}
export default plugin;
export { Interaction, plugin as install };