/** * @fileoverview 视角轨迹动画 * 主入口类是TrackAnimation, * 基于Baidu Map API GL 1.0。 * * @author Baidu Map Api Group * @version 1.0 */ /** * @namespace BMapGL的所有library类均放在BMapGLLib命名空间下 */ var BMapGLLib = window.BMapGLLib = BMapGLLib || {}; (function () { var DELTA_ZOOM = 1; var DEFAULT_TILT = 55; var DEFAULT_HEADING = 0; var DEFAULT_DURATION = 10000; var DEFAULT_DELAY = 0; var DEFAULT_OVERALLVIEW = true; var PLAY = 1; var CANCEL = 2; var PAUSE = 3; var start = 0; var TrackAnimation = /** * 构造函数 * * @param {BMapGL.Map} map 地图实例 * @param {Polyline} polyline 折线实例 * @param {TrackAnimationOptions} opts 配置 * { * zoom * tilt * duration * delay * overallView * } */ BMapGLLib.TrackAnimation = function (map, polyline, opts) { this._map = map; this._polyline = polyline; this._totalPath = polyline.getPath(); this._overallView = map.getViewport(polyline.getPath()); this._status = CANCEL; this._opts = { zoom: this._getZoom(), tilt: DEFAULT_TILT, heading: DEFAULT_HEADING, duration: DEFAULT_DURATION, delay: DEFAULT_DELAY, overallView: DEFAULT_OVERALLVIEW }; this._initOpts(opts); this._expandPath = this._addPath(polyline.getPath()); // window.requestAnimationFrame(this._step); // 暂停时累计经历的时间 this._pauseTime = 0; }; /** * 获取轨迹播放合适的缩放级别 * @return {number} zoom */ TrackAnimation.prototype._getZoom = function () { return Math.min(this._overallView.zoom + DELTA_ZOOM, this._map.getMaxZoom()); }; /** * 根据当前配置更新动画参数 */ TrackAnimation.prototype._updateAniParams = function () { this._updatePathAni(); this._updateViewAni(); this._polyline.setPath(this._expandPath.slice(0, 1)); }; /** * 轨迹动画 */ TrackAnimation.prototype._updatePathAni = function () { this._expandPath = this._addPath(this._totalPath); }; /** * 视角动画 */ TrackAnimation.prototype._updateViewAni = function () { this._overallView = this._map.getViewport(this._totalPath); var length = this._totalPath.length; var keyFrames = []; var duration = this._opts.overallView ? this._opts.duration + 2000 : this._opts.duration; for (var i = 0; i < length; i++) { var item = this._totalPath[i]; var percent = this._pathPercents[i] * (this._opts.duration / duration) keyFrames.push({ center: new BMapGL.Point(item.lng, item.lat), zoom: this._opts.zoom, tilt: i === 0 ? 0 : this._opts.tilt, heading: i === 0 ? 0 : this._opts.heading, percentage: percent }); } if (this._opts.overallView) { keyFrames.push({ center: new BMapGL.Point(this._overallView.center.lng, this._overallView.center.lat), zoom: this._overallView.zoom - DELTA_ZOOM, tilt: 0, heading: 0, percentage: 1 }); } var opts = { duration: duration, delay: 0, interation: 1 }; this._viewAni = new BMapGL.ViewAnimation(keyFrames, opts); }; /** * 扩充Path * @param {Array} path 原始路径 */ TrackAnimation.prototype._addPath = function (path) { var TOTAL_NUM = this._opts.duration / 10; var length = path.length; var totalDistance = 0; var distances = []; var expandPath = []; for (var i = 1; i < length; i++) { var distance = this._map.getDistance(path[i - 1], path[i]); distances.push(distance); totalDistance += distance; } var percents = [0]; for (var i = 1; i < length; i++) { var percent = (distances[i - 1] / totalDistance).toFixed(2); // percents.push(percent); percents[i] = percents[i - 1] + parseFloat(percent, 10); expandPath = expandPath.concat(this._getPath(path[i - 1], path[i], percent * TOTAL_NUM)); } this._pathPercents = percents; return expandPath; }; /** * 获取差值Path * @param {Object} start 起始点 * @param {Object} end 终止点 * @param {number} num 差值点数量 */ TrackAnimation.prototype._getPath = function (start, end, num) { var result = []; if (num === 0) { return result; } for (var i = 0; i <= num; i++) { var point = new BMapGL.Point( (end.lng - start.lng) / num * i + start.lng, (end.lat - start.lat) / num * i + start.lat ); result.push(point); } return result; } /** * 初始化配置参数 * @param {Object} opts 配置 */ TrackAnimation.prototype._initOpts = function (opts) { for (var p in opts) { if (opts.hasOwnProperty(p)) { this._opts[p] = opts[p]; } } }; /** * 启动动画 */ TrackAnimation.prototype.start = function () { var me = this; setTimeout(function () { me._updateAniParams(); me._map.removeOverlay(me._polyline); me._map.addOverlay(me._polyline); me._status = PLAY; me._step(performance.now()); me._map.startViewAnimation(me._viewAni); }, this._opts.delay); }; /** * 终止动画 */ TrackAnimation.prototype.cancel = function () { this._clearRAF(); this._status = CANCEL; start = 0; this._pauseTime = 0; this._map.cancelViewAnimation(this._viewAni); this._map.removeOverlay(this._polyline); }; /** * 暂停动画 */ TrackAnimation.prototype.pause = function () { if (this._status === PLAY) { this._clearRAF(); this._map.pauseViewAnimation(this._viewAni); this._status = PAUSE; this._isPausing = performance.now(); } }; /** * 继续动画 */ TrackAnimation.prototype.continue = function () { if (this._status === PAUSE) { this._pauseTime += performance.now() - this._isPausing; this._isPausing = undefined; this._status = PLAY; this._step(performance.now()); this._map.continueViewAnimation(this._viewAni); } }; /** * rAF动画函数 * @param {number} timestamp 时间戳 */ TrackAnimation.prototype._step = function (timestamp) { if (this._status === CANCEL) { start = 0; return; } if (!start) { start = timestamp; } timestamp = timestamp - this._pauseTime; var percent = (timestamp - start) / this._opts.duration; var end = Math.round(this._expandPath.length * percent); this._polyline.setPath(this._expandPath.slice(0, end)); if (timestamp < start + this._opts.duration) { this._timer = window.requestAnimationFrame(this._step.bind(this)); } else { start = 0; this._status = CANCEL; this._pauseTime = 0; } }; /** * 清除rAF动画函数 */ TrackAnimation.prototype._clearRAF = function () { if (this._timer) { window.cancelAnimationFrame(this._timer); } }; /** * 设置缩放级别 * @param {number} zoom 缩放级别 */ TrackAnimation.prototype.setZoom = function (zoom) { this._opts.zoom = zoom; }; /** * 获取缩放级别 * @return {number} zoom */ TrackAnimation.prototype.getZoom = function (zoom) { return this._opts.zoom; }; /** * 设置角度 * @param {number} tilt 角度 */ TrackAnimation.prototype.setTilt = function (tilt) { this._opts.tilt = tilt; }; /** * 获取角度 * @return {number} tilt */ TrackAnimation.prototype.getTilt = function (tilt) { return this._opts.tilt; }; /** * 设置延迟 * @param {number} delay 延迟 */ TrackAnimation.prototype.setDelay = function (delay) { this._opts.delay = delay; }; /** * 获取延迟 * @return {number} delay */ TrackAnimation.prototype.getDelay = function (delay) { return this._opts.delay; }; /** * 设置持续事件 * @param {number} duration 持续事件 */ TrackAnimation.prototype.setDuration = function (duration) { this._opts.duration = duration; }; /** * 获取持续事件 * @return {number} duration */ TrackAnimation.prototype.getDuration = function (duration) { return this._opts.duration; }; /** * 开启总览 */ TrackAnimation.prototype.enableOverallView = function () { this._opts.overallView = true; }; /** * 关闭总览 */ TrackAnimation.prototype.disableOverallView = function () { this._opts.overallView = false; }; /** * 更新折线 * @param {Object} polyline 更新 */ TrackAnimation.prototype.setPolyline = function (polyline) { this._polyline = polyline; this._totalPath = polyline.getPath(); }; /** * 获取折线 * @return {Object} polyline */ TrackAnimation.prototype.getPolyline = function () { return this._polyline; }; })();