UNPKG

kmap-ui

Version:

A components of zmap base on vue2.X

292 lines (263 loc) 10.1 kB
/* Copyright (c) 2016 Jean-Marc VIGLINO, released under the CeCILL license (http://www.cecill.info/). */ import ol_ext_inherits from '../util/ext' import ol_Object from 'ol/Object' import {linear as ol_easing_linear} from 'ol/easing' import ol_Map from 'ol/Map' import {getCenter as ol_extent_getCenter} from 'ol/extent' import {unByKey as ol_Observable_unByKey} from 'ol/Observable' import ol_layer_Base from 'ol/layer/Base' import ol_style_Style from 'ol/style/Style' import ol_style_Circle from 'ol/style/Circle' import ol_style_Stroke from 'ol/style/Stroke' import ol_layer_Vector from 'ol/layer/Vector' import ol_source_Vector from 'ol/source/Vector' import ol_render_getVectorContext from '../util/getVectorContext'; /** Feature animation base class * Use the {@link _ol_Map_#animateFeature} or {@link _ol_layer_Vector_#animateFeature} to animate a feature * on postcompose in a map or a layer * @constructor * @fires animationstart * @fires animating * @fires animationend * @param {ol_featureAnimationOptions} options * @param {Number} options.duration duration of the animation in ms, default 1000 * @param {bool} options.revers revers the animation direction * @param {Number} options.repeat number of time to repeat the animation, default 0 * @param {ol.style.Style} options.hiddenStyle a style to display the feature when playing the animation * to be used to make the feature selectable when playing animation * (@see {@link ../examples/map.featureanimation.select.html}), default the feature * will be hidden when playing (and not selectable) * @param {ol_easing_Function} options.fade an easing function used to fade in the feature, default none * @param {ol_easing_Function} options.easing an easing function for the animation, default ol_easing_linear */ var ol_featureAnimation = function(options) { options = options || {}; this.duration_ = typeof (options.duration)=='number' ? (options.duration>=0 ? options.duration : 0) : 1000; this.fade_ = typeof(options.fade) == 'function' ? options.fade : null; this.repeat_ = Number(options.repeat); var easing = typeof(options.easing) =='function' ? options.easing : ol_easing_linear; if (options.revers) this.easing_ = function(t) { return (1 - easing(t)); }; else this.easing_ = easing; this.hiddenStyle = options.hiddenStyle; ol_Object.call(this); }; ol_ext_inherits(ol_featureAnimation, ol_Object); /** Hidden style: a transparent style */ ol_featureAnimation.hiddenStyle = new ol_style_Style({ image: new ol_style_Circle({}), stroke: new ol_style_Stroke({ color: 'transparent' }) }); /** Draw a geometry * @param {olx.animateFeatureEvent} e * @param {ol.geom} geom geometry for shadow * @param {ol.geom} shadow geometry for shadow (ie. style with zIndex = -1) * @private */ ol_featureAnimation.prototype.drawGeom_ = function (e, geom, shadow) { if (this.fade_) { e.context.globalAlpha = this.fade_(1-e.elapsed); } var style = e.style; for (var i=0; i<style.length; i++) { // Prevent crach if the style is not ready (image not loaded) try { var vectorContext = e.vectorContext || ol_render_getVectorContext(e); vectorContext.setStyle(style[i]); if (style[i].getZIndex()<0) vectorContext.drawGeometry(shadow||geom); else vectorContext.drawGeometry(geom); } catch(e) { /* ok */ } } }; /** Function to perform manipulations onpostcompose. * This function is called with an ol_featureAnimationEvent argument. * The function will be overridden by the child implementation. * Return true to keep this function for the next frame, false to remove it. * @param {ol_featureAnimationEvent} e * @return {bool} true to continue animation. * @api */ ol_featureAnimation.prototype.animate = function (/* e */) { return false; }; /** An animation controler object an object to control animation with start, stop and isPlaying function. * To be used with {@link olx.Map#animateFeature} or {@link ol.layer.Vector#animateFeature} * @typedef {Object} ol.animationControler * @property {function} start - start animation. * @property {function} stop - stop animation option arguments can be passed in animationend event. * @property {function} isPlaying - return true if animation is playing. */ /** Animate feature on a map * @function * @param {ol.Feature} feature Feature to animate * @param {ol_featureAnimation|Array<ol_featureAnimation>} fanim the animation to play * @return {olx.animationControler} an object to control animation with start, stop and isPlaying function */ ol_Map.prototype.animateFeature = function(feature, fanim) { // Get or create an animation layer associated with the map var layer = this._featureAnimationLayer; if (!layer) { layer = this._featureAnimationLayer = new ol_layer_Vector({ source: new ol_source_Vector() }); layer.setMap(this); } // Animate feature on this layer layer.getSource().addFeature(feature); var listener = fanim.on('animationend', function(e) { if (e.feature===feature) { // Remove feature on end layer.getSource().removeFeature(feature); ol_Observable_unByKey(listener); } }); layer.animateFeature(feature, fanim); }; /** Animate feature on a vector layer * @fires animationstart, animationend * @param {ol.Feature} feature Feature to animate * @param {ol_featureAnimation|Array<ol_featureAnimation>} fanim the animation to play * @param {boolean} useFilter use the filters of the layer * @return {olx.animationControler} an object to control animation with start, stop and isPlaying function */ ol_layer_Base.prototype.animateFeature = function(feature, fanim, useFilter) { var self = this; var listenerKey; // Save style var style = feature.getStyle(); var flashStyle = style || (this.getStyleFunction ? this.getStyleFunction()(feature) : null); if (!flashStyle) flashStyle=[]; if (!(flashStyle instanceof Array)) flashStyle = [flashStyle]; // Structure pass for animating var event = { // Frame context vectorContext: null, frameState: null, start: 0, time: 0, elapsed: 0, extent: false, // Feature information feature: feature, geom: feature.getGeometry(), typeGeom: feature.getGeometry().getType(), bbox: feature.getGeometry().getExtent(), coord: ol_extent_getCenter(feature.getGeometry().getExtent()), style: flashStyle }; if (!(fanim instanceof Array)) fanim = [fanim]; // Remove null animations for (var i=fanim.length-1; i>=0; i--) { if (fanim[i].duration_===0) fanim.splice(i,1); } var nb=0, step = 0; // Filter availiable on the layer var filters = (useFilter && this.getFilters) ? this.getFilters() : []; function animate(e) { event.type = e.type; try { event.vectorContext = e.vectorContext || ol_render_getVectorContext(e); } catch(e) { /* nothing todo */ } event.frameState = e.frameState; event.inversePixelTransform = e.inversePixelTransform; if (!event.extent) { event.extent = e.frameState.extent; event.start = e.frameState.time; event.context = e.context; } event.time = e.frameState.time - event.start; event.elapsed = event.time / fanim[step].duration_; if (event.elapsed > 1) event.elapsed = 1; // Filter e.context.save(); filters.forEach(function(f) { if (f.get('active')) f.precompose(e); }); if (this.getOpacity) { e.context.globalAlpha = this.getOpacity(); } // Stop animation? if (!fanim[step].animate(event)) { nb++; // Repeat animation if (nb < fanim[step].repeat_) { event.extent = false; } else if (step < fanim.length-1) { // newt step fanim[step].dispatchEvent({ type:'animationend', feature: feature }); step++; nb=0; event.extent = false; } else { // the end stop(); } } else { var animEvent = { type: 'animating', step: step, start: event.start, time: event.time, elapsed: event.elapsed, rotation: event.rotation||0, geom: event.geom, coordinate: event.coord, feature: feature }; fanim[step].dispatchEvent(animEvent); self.dispatchEvent(animEvent); } filters.forEach(function(f) { if (f.get('active')) f.postcompose(e); }); e.context.restore(); // tell OL3 to continue postcompose animation e.frameState.animate = true; } // Stop animation function stop(options) { ol_Observable_unByKey(listenerKey); listenerKey = null; feature.setStyle(style); // Send event var event = { type:'animationend', feature: feature }; if (options) { for (var i in options) if (options.hasOwnProperty(i)) { event[i] = options[i]; } } fanim[step].dispatchEvent(event); self.dispatchEvent(event); } // Launch animation function start(options) { if (fanim.length && !listenerKey) { listenerKey = self.on(['postcompose','postrender'], animate.bind(self)); // map or layer? if (self.renderSync) self.renderSync(); else self.changed(); // Hide feature while animating feature.setStyle(fanim[step].hiddenStyle || ol_featureAnimation.hiddenStyle); // Send event var event = { type:'animationstart', feature: feature }; if (options) { for (var i in options) if (options.hasOwnProperty(i)) { event[i] = options[i]; } } fanim[step].dispatchEvent(event); self.dispatchEvent(event); } } start(); // Return animation controler return { start: start, stop: stop, isPlaying: function() { return (!!listenerKey); } }; }; export default ol_featureAnimation