123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792 |
- /*global define*/
- define([
- '../../Core/ClockRange',
- '../../Core/defined',
- '../../Core/destroyObject',
- '../../Core/DeveloperError',
- '../../Core/JulianDate',
- '../getElement',
- './TimelineHighlightRange',
- './TimelineTrack'
- ], function(
- ClockRange,
- defined,
- destroyObject,
- DeveloperError,
- JulianDate,
- getElement,
- TimelineHighlightRange,
- TimelineTrack) {
- "use strict";
- var timelineWheelDelta = 1e12;
- var timelineMouseMode = {
- none : 0,
- scrub : 1,
- slide : 2,
- zoom : 3,
- touchOnly : 4
- };
- var timelineTouchMode = {
- none : 0,
- scrub : 1,
- slideZoom : 2,
- singleTap : 3,
- ignore : 4
- };
- var timelineTicScales = [0.001, 0.002, 0.005, 0.01, 0.02, 0.05, 0.1, 0.25, 0.5, 1.0, 2.0, 5.0, 10.0, 15.0, 30.0, 60.0, // 1min
- 120.0, // 2min
- 300.0, // 5min
- 600.0, // 10min
- 900.0, // 15min
- 1800.0, // 30min
- 3600.0, // 1hr
- 7200.0, // 2hr
- 14400.0, // 4hr
- 21600.0, // 6hr
- 43200.0, // 12hr
- 86400.0, // 24hr
- 172800.0, // 2days
- 345600.0, // 4days
- 604800.0, // 7days
- 1296000.0, // 15days
- 2592000.0, // 30days
- 5184000.0, // 60days
- 7776000.0, // 90days
- 15552000.0, // 180days
- 31536000.0, // 365days
- 63072000.0, // 2years
- 126144000.0, // 4years
- 157680000.0, // 5years
- 315360000.0, // 10years
- 630720000.0, // 20years
- 1261440000.0, // 40years
- 1576800000.0, // 50years
- 3153600000.0, // 100years
- 6307200000.0, // 200years
- 12614400000.0, // 400years
- 15768000000.0, // 500years
- 31536000000.0 // 1000years
- ];
- var timelineMonthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
- /**
- * The Timeline is a widget for displaying and controlling the current scene time.
- * @alias Timeline
- * @constructor
- *
- * @param {Element} container The parent HTML container node for this widget.
- * @param {Clock} clock The clock to use.
- */
- var Timeline = function(container, clock) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(container)) {
- throw new DeveloperError('container is required.');
- }
- if (!defined(clock)) {
- throw new DeveloperError('clock is required.');
- }
- //>>includeEnd('debug');
- container = getElement(container);
- /**
- * Gets the parent container.
- * @type {Element}
- */
- this.container = container;
- var topDiv = document.createElement('div');
- topDiv.className = 'cesium-timeline-main';
- container.appendChild(topDiv);
- this._topDiv = topDiv;
- this._endJulian = undefined;
- this._epochJulian = undefined;
- this._lastXPos = undefined;
- this._scrubElement = undefined;
- this._startJulian = undefined;
- this._timeBarSecondsSpan = undefined;
- this._clock = clock;
- this._scrubJulian = clock.currentTime;
- this._mainTicSpan = -1;
- this._mouseMode = timelineMouseMode.none;
- this._touchMode = timelineTouchMode.none;
- this._touchState = {
- centerX : 0,
- spanX : 0
- };
- this._mouseX = 0;
- this._timelineDrag = 0;
- this._timelineDragLocation = undefined;
- this._lastHeight = undefined;
- this._lastWidth = undefined;
- this._topDiv.innerHTML = '<div class="cesium-timeline-bar"></div><div class="cesium-timeline-trackContainer">' +
- '<canvas class="cesium-timeline-tracks" width="10" height="1">' +
- '</canvas></div><div class="cesium-timeline-needle"></div><span class="cesium-timeline-ruler"></span>';
- this._timeBarEle = this._topDiv.childNodes[0];
- this._trackContainer = this._topDiv.childNodes[1];
- this._trackListEle = this._topDiv.childNodes[1].childNodes[0];
- this._needleEle = this._topDiv.childNodes[2];
- this._rulerEle = this._topDiv.childNodes[3];
- this._context = this._trackListEle.getContext('2d');
- this._trackList = [];
- this._highlightRanges = [];
- this.zoomTo(clock.startTime, clock.stopTime);
- this._onMouseDown = createMouseDownCallback(this);
- this._onMouseUp = createMouseUpCallback(this);
- this._onMouseMove = createMouseMoveCallback(this);
- this._onMouseWheel = createMouseWheelCallback(this);
- this._onTouchStart = createTouchStartCallback(this);
- this._onTouchMove = createTouchMoveCallback(this);
- this._onTouchEnd = createTouchEndCallback(this);
- var timeBarEle = this._timeBarEle;
- document.addEventListener('mouseup', this._onMouseUp, false);
- document.addEventListener('mousemove', this._onMouseMove, false);
- timeBarEle.addEventListener('mousedown', this._onMouseDown, false);
- timeBarEle.addEventListener('DOMMouseScroll', this._onMouseWheel, false); // Mozilla mouse wheel
- timeBarEle.addEventListener('mousewheel', this._onMouseWheel, false);
- timeBarEle.addEventListener('touchstart', this._onTouchStart, false);
- timeBarEle.addEventListener('touchmove', this._onTouchMove, false);
- timeBarEle.addEventListener('touchend', this._onTouchEnd, false);
- this._topDiv.oncontextmenu = function() {
- return false;
- };
- clock.onTick.addEventListener(this.updateFromClock, this);
- this.updateFromClock();
- };
- /**
- * @private
- */
- Timeline.prototype.addEventListener = function(type, listener, useCapture) {
- this._topDiv.addEventListener(type, listener, useCapture);
- };
- /**
- * @private
- */
- Timeline.prototype.removeEventListener = function(type, listener, useCapture) {
- this._topDiv.removeEventListener(type, listener, useCapture);
- };
- /**
- * @returns {Boolean} true if the object has been destroyed, false otherwise.
- */
- Timeline.prototype.isDestroyed = function() {
- return false;
- };
- /**
- * Destroys the widget. Should be called if permanently
- * removing the widget from layout.
- */
- Timeline.prototype.destroy = function() {
- this._clock.onTick.removeEventListener(this.updateFromClock, this);
- document.removeEventListener('mouseup', this._onMouseUp, false);
- document.removeEventListener('mousemove', this._onMouseMove, false);
- var timeBarEle = this._timeBarEle;
- timeBarEle.removeEventListener('mousedown', this._onMouseDown, false);
- timeBarEle.removeEventListener('DOMMouseScroll', this._onMouseWheel, false); // Mozilla mouse wheel
- timeBarEle.removeEventListener('mousewheel', this._onMouseWheel, false);
- timeBarEle.removeEventListener('touchstart', this._onTouchStart, false);
- timeBarEle.removeEventListener('touchmove', this._onTouchMove, false);
- timeBarEle.removeEventListener('touchend', this._onTouchEnd, false);
- this.container.removeChild(this._topDiv);
- destroyObject(this);
- };
- /**
- * @private
- */
- Timeline.prototype.addHighlightRange = function(color, heightInPx, base) {
- var newHighlightRange = new TimelineHighlightRange(color, heightInPx, base);
- this._highlightRanges.push(newHighlightRange);
- this.resize();
- return newHighlightRange;
- };
- /**
- * @private
- */
- Timeline.prototype.addTrack = function(interval, heightInPx, color, backgroundColor) {
- var newTrack = new TimelineTrack(interval, heightInPx, color, backgroundColor);
- this._trackList.push(newTrack);
- this._lastHeight = undefined;
- this.resize();
- return newTrack;
- };
- /**
- * Sets the view to the provided times.
- *
- * @param {JulianDate} startTime The start time.
- * @param {JulianDate} stopTime The stop time.
- */
- Timeline.prototype.zoomTo = function(startTime, stopTime) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(startTime)) {
- throw new DeveloperError('startTime is required.');
- }
- if (!defined(stopTime)) {
- throw new DeveloperError('stopTime is required');
- }
- if (JulianDate.lessThanOrEquals(stopTime, startTime)) {
- throw new DeveloperError('Start time must come before end time.');
- }
- //>>includeEnd('debug');
- this._startJulian = startTime;
- this._endJulian = stopTime;
- this._timeBarSecondsSpan = JulianDate.secondsDifference(stopTime, startTime);
- // If clock is not unbounded, clamp timeline range to clock.
- if (this._clock && (this._clock.clockRange !== ClockRange.UNBOUNDED)) {
- var clockStart = this._clock.startTime;
- var clockEnd = this._clock.stopTime;
- var clockSpan = JulianDate.secondsDifference(clockEnd, clockStart);
- var startOffset = JulianDate.secondsDifference(clockStart, this._startJulian);
- var endOffset = JulianDate.secondsDifference(clockEnd, this._endJulian);
- if (this._timeBarSecondsSpan >= clockSpan) {
- // if new duration longer than clock range duration, clamp to full range.
- this._timeBarSecondsSpan = clockSpan;
- this._startJulian = this._clock.startTime;
- this._endJulian = this._clock.stopTime;
- } else if (startOffset > 0) {
- // if timeline start is before clock start, shift right
- this._endJulian = JulianDate.addSeconds(this._endJulian, startOffset, new JulianDate());
- this._startJulian = clockStart;
- this._timeBarSecondsSpan = JulianDate.secondsDifference(this._endJulian, this._startJulian);
- } else if (endOffset < 0) {
- // if timeline end is after clock end, shift left
- this._startJulian = JulianDate.addSeconds(this._startJulian, endOffset, new JulianDate());
- this._endJulian = clockEnd;
- this._timeBarSecondsSpan = JulianDate.secondsDifference(this._endJulian, this._startJulian);
- }
- }
- this._makeTics();
- var evt = document.createEvent('Event');
- evt.initEvent('setzoom', true, true);
- evt.startJulian = this._startJulian;
- evt.endJulian = this._endJulian;
- evt.epochJulian = this._epochJulian;
- evt.totalSpan = this._timeBarSecondsSpan;
- evt.mainTicSpan = this._mainTicSpan;
- this._topDiv.dispatchEvent(evt);
- };
- /**
- * @private
- */
- Timeline.prototype.zoomFrom = function(amount) {
- var centerSec = JulianDate.secondsDifference(this._scrubJulian, this._startJulian);
- if ((amount > 1) || (centerSec < 0) || (centerSec > this._timeBarSecondsSpan)) {
- centerSec = this._timeBarSecondsSpan * 0.5;
- } else {
- centerSec += (centerSec - this._timeBarSecondsSpan * 0.5);
- }
- var centerSecFlip = this._timeBarSecondsSpan - centerSec;
- this.zoomTo(JulianDate.addSeconds(this._startJulian, centerSec - (centerSec * amount), new JulianDate()), JulianDate.addSeconds(this._endJulian, (centerSecFlip * amount) - centerSecFlip, new JulianDate()));
- };
- function twoDigits(num) {
- return ((num < 10) ? ('0' + num.toString()) : num.toString());
- }
- /**
- * @private
- */
- Timeline.prototype.makeLabel = function(time) {
- var gregorian = JulianDate.toGregorianDate(time);
- var millisecond = gregorian.millisecond, millisecondString = ' UTC';
- if ((millisecond > 0) && (this._timeBarSecondsSpan < 3600)) {
- millisecondString = Math.floor(millisecond).toString();
- while (millisecondString.length < 3) {
- millisecondString = '0' + millisecondString;
- }
- millisecondString = '.' + millisecondString;
- }
- return timelineMonthNames[gregorian.month - 1] + ' ' + gregorian.day + ' ' + gregorian.year + ' ' + twoDigits(gregorian.hour) +
- ':' + twoDigits(gregorian.minute) + ':' + twoDigits(gregorian.second) + millisecondString;
- };
- /**
- * @private
- */
- Timeline.prototype.smallestTicInPixels = 7.0;
- /**
- * @private
- */
- Timeline.prototype._makeTics = function() {
- var timeBar = this._timeBarEle;
- var seconds = JulianDate.secondsDifference(this._scrubJulian, this._startJulian);
- var xPos = Math.round(seconds * this._topDiv.clientWidth / this._timeBarSecondsSpan);
- var scrubX = xPos - 8, tic;
- var widget = this;
- this._needleEle.style.left = xPos.toString() + 'px';
- var tics = '';
- var minimumDuration = 0.01;
- var maximumDuration = 31536000000.0; // ~1000 years
- var epsilon = 1e-10;
- // If time step size is known, enter it here...
- var minSize = 0;
- var duration = this._timeBarSecondsSpan;
- if (duration < minimumDuration) {
- duration = minimumDuration;
- this._timeBarSecondsSpan = minimumDuration;
- this._endJulian = JulianDate.addSeconds(this._startJulian, minimumDuration, new JulianDate());
- } else if (duration > maximumDuration) {
- duration = maximumDuration;
- this._timeBarSecondsSpan = maximumDuration;
- this._endJulian = JulianDate.addSeconds(this._startJulian, maximumDuration, new JulianDate());
- }
- var timeBarWidth = this._timeBarEle.clientWidth;
- if (timeBarWidth < 10) {
- timeBarWidth = 10;
- }
- var startJulian = this._startJulian;
- // epsilonTime: a small fraction of one pixel width of the timeline, measured in seconds.
- var epsilonTime = Math.min((duration / timeBarWidth) * 1e-5, 0.4);
- // epochJulian: a nearby time to be considered "zero seconds", should be a round-ish number by human standards.
- var epochJulian;
- if (duration > 315360000) { // 3650+ days visible, epoch is start of the first visible century.
- epochJulian = JulianDate.fromIso8601(JulianDate.toDate(startJulian).toISOString().substring(0, 2) + '00-01-01T00:00:00Z');
- } else if (duration > 31536000) { // 365+ days visible, epoch is start of the first visible decade.
- epochJulian = JulianDate.fromIso8601(JulianDate.toDate(startJulian).toISOString().substring(0, 3) + '0-01-01T00:00:00Z');
- } else if (duration > 86400) { // 1+ day(s) visible, epoch is start of the year.
- epochJulian = JulianDate.fromIso8601(JulianDate.toDate(startJulian).toISOString().substring(0, 4) + '-01-01T00:00:00Z');
- } else { // Less than a day on timeline, epoch is midnight of the visible day.
- epochJulian = JulianDate.fromIso8601(JulianDate.toDate(startJulian).toISOString().substring(0, 10) + 'T00:00:00Z');
- }
- // startTime: Seconds offset of the left side of the timeline from epochJulian.
- var startTime = JulianDate.secondsDifference(this._startJulian, JulianDate.addSeconds(epochJulian, epsilonTime, new JulianDate()));
- // endTime: Seconds offset of the right side of the timeline from epochJulian.
- var endTime = startTime + duration;
- this._epochJulian = epochJulian;
- function getStartTic(ticScale) {
- return Math.floor(startTime / ticScale) * ticScale;
- }
- function getNextTic(tic, ticScale) {
- return Math.ceil((tic / ticScale) + 0.5) * ticScale;
- }
- function getAlpha(time) {
- return (time - startTime) / duration;
- }
- function remainder(x, y) {
- //return x % y;
- return x - (y * Math.round(x / y));
- }
- // Width in pixels of a typical label, plus padding
- this._rulerEle.innerHTML = this.makeLabel(JulianDate.addSeconds(this._endJulian, -minimumDuration, new JulianDate()));
- var sampleWidth = this._rulerEle.offsetWidth + 20;
- if (sampleWidth < 30) {
- // Workaround an apparent IE bug with measuring the width after going full-screen from inside an iframe.
- sampleWidth = 180;
- }
- var origMinSize = minSize;
- minSize -= epsilon;
- var renderState = {
- startTime : startTime,
- startJulian : startJulian,
- epochJulian : epochJulian,
- duration : duration,
- timeBarWidth : timeBarWidth,
- getAlpha : getAlpha
- };
- this._highlightRanges.forEach(function(highlightRange) {
- tics += highlightRange.render(renderState);
- });
- // Calculate tic mark label spacing in the TimeBar.
- var mainTic = 0.0, subTic = 0.0, tinyTic = 0.0;
- // Ideal labeled tic as percentage of zoom interval
- var idealTic = sampleWidth / timeBarWidth;
- if (idealTic > 1.0) {
- // Clamp to width of window, for thin windows.
- idealTic = 1.0;
- }
- // Ideal labeled tic size in seconds
- idealTic *= this._timeBarSecondsSpan;
- var ticIndex = -1, smallestIndex = -1;
- var i, ticScaleLen = timelineTicScales.length;
- for (i = 0; i < ticScaleLen; ++i) {
- var sc = timelineTicScales[i];
- ++ticIndex;
- mainTic = sc;
- // Find acceptable main tic size not smaller than ideal size.
- if ((sc > idealTic) && (sc > minSize)) {
- break;
- }
- if ((smallestIndex < 0) && ((timeBarWidth * (sc / this._timeBarSecondsSpan)) >= this.smallestTicInPixels)) {
- smallestIndex = ticIndex;
- }
- }
- if (ticIndex > 0) {
- while (ticIndex > 0) // Compute sub-tic size that evenly divides main tic.
- {
- --ticIndex;
- if (Math.abs(remainder(mainTic, timelineTicScales[ticIndex])) < 0.00001) {
- if (timelineTicScales[ticIndex] >= minSize) {
- subTic = timelineTicScales[ticIndex];
- }
- break;
- }
- }
- if (smallestIndex >= 0) {
- while (smallestIndex < ticIndex) // Compute tiny tic size that evenly divides sub-tic.
- {
- if ((Math.abs(remainder(subTic, timelineTicScales[smallestIndex])) < 0.00001) && (timelineTicScales[smallestIndex] >= minSize)) {
- tinyTic = timelineTicScales[smallestIndex];
- break;
- }
- ++smallestIndex;
- }
- }
- }
- minSize = origMinSize;
- if ((minSize > epsilon) && (tinyTic < 0.00001) && (Math.abs(minSize - mainTic) > epsilon)) {
- tinyTic = minSize;
- if (minSize <= (mainTic + epsilon)) {
- subTic = 0.0;
- }
- }
- var lastTextLeft = -999999, textWidth;
- if ((timeBarWidth * (tinyTic / this._timeBarSecondsSpan)) >= 3.0) {
- for (tic = getStartTic(tinyTic); tic <= endTime; tic = getNextTic(tic, tinyTic)) {
- tics += '<span class="cesium-timeline-ticTiny" style="left: ' + Math.round(timeBarWidth * getAlpha(tic)).toString() + 'px;"></span>';
- }
- }
- if ((timeBarWidth * (subTic / this._timeBarSecondsSpan)) >= 3.0) {
- for (tic = getStartTic(subTic); tic <= endTime; tic = getNextTic(tic, subTic)) {
- tics += '<span class="cesium-timeline-ticSub" style="left: ' + Math.round(timeBarWidth * getAlpha(tic)).toString() + 'px;"></span>';
- }
- }
- if ((timeBarWidth * (mainTic / this._timeBarSecondsSpan)) >= 2.0) {
- this._mainTicSpan = mainTic;
- endTime += mainTic;
- tic = getStartTic(mainTic);
- var leapSecond = JulianDate.computeTaiMinusUtc(epochJulian);
- while (tic <= endTime) {
- var ticTime = JulianDate.addSeconds(startJulian, tic - startTime, new JulianDate());
- if (mainTic > 2.1) {
- var ticLeap = JulianDate.computeTaiMinusUtc(ticTime);
- if (Math.abs(ticLeap - leapSecond) > 0.1) {
- tic += (ticLeap - leapSecond);
- ticTime = JulianDate.addSeconds(startJulian, tic - startTime, new JulianDate());
- }
- }
- var ticLeft = Math.round(timeBarWidth * getAlpha(tic));
- var ticLabel = this.makeLabel(ticTime);
- this._rulerEle.innerHTML = ticLabel;
- textWidth = this._rulerEle.offsetWidth;
- if (textWidth < 10) {
- // IE iframe fullscreen sampleWidth workaround, continued.
- textWidth = sampleWidth;
- }
- var labelLeft = ticLeft - ((textWidth / 2) - 1);
- if (labelLeft > lastTextLeft) {
- lastTextLeft = labelLeft + textWidth + 5;
- tics += '<span class="cesium-timeline-ticMain" style="left: ' + ticLeft.toString() + 'px;"></span>' + '<span class="cesium-timeline-ticLabel" style="left: ' + labelLeft.toString() +
- 'px;">' + ticLabel + '</span>';
- } else {
- tics += '<span class="cesium-timeline-ticSub" style="left: ' + ticLeft.toString() + 'px;"></span>';
- }
- tic = getNextTic(tic, mainTic);
- }
- } else {
- this._mainTicSpan = -1;
- }
- tics += '<span class="cesium-timeline-icon16" style="left:' + scrubX + 'px;bottom:0;background-position: 0px 0px;"></span>';
- timeBar.innerHTML = tics;
- this._scrubElement = timeBar.lastChild;
- // Clear track canvas.
- this._context.clearRect(0, 0, this._trackListEle.width, this._trackListEle.height);
- renderState.y = 0;
- this._trackList.forEach(function(track) {
- track.render(widget._context, renderState);
- renderState.y += track.height;
- });
- };
- /**
- * @private
- */
- Timeline.prototype.updateFromClock = function() {
- this._scrubJulian = this._clock.currentTime;
- var scrubElement = this._scrubElement;
- if (defined(this._scrubElement)) {
- var seconds = JulianDate.secondsDifference(this._scrubJulian, this._startJulian);
- var xPos = Math.round(seconds * this._topDiv.clientWidth / this._timeBarSecondsSpan);
- if (this._lastXPos !== xPos) {
- this._lastXPos = xPos;
- scrubElement.style.left = (xPos - 8) + 'px';
- this._needleEle.style.left = xPos + 'px';
- }
- }
- if (defined(this._timelineDragLocation)) {
- this._setTimeBarTime(this._timelineDragLocation, this._timelineDragLocation * this._timeBarSecondsSpan / this._topDiv.clientWidth);
- this.zoomTo(JulianDate.addSeconds(this._startJulian, this._timelineDrag, new JulianDate()), JulianDate.addSeconds(this._endJulian, this._timelineDrag, new JulianDate()));
- }
- };
- /**
- * @private
- */
- Timeline.prototype._setTimeBarTime = function(xPos, seconds) {
- xPos = Math.round(xPos);
- this._scrubJulian = JulianDate.addSeconds(this._startJulian, seconds, new JulianDate());
- if (this._scrubElement) {
- var scrubX = xPos - 8;
- this._scrubElement.style.left = scrubX.toString() + 'px';
- this._needleEle.style.left = xPos.toString() + 'px';
- }
- var evt = document.createEvent('Event');
- evt.initEvent('settime', true, true);
- evt.clientX = xPos;
- evt.timeSeconds = seconds;
- evt.timeJulian = this._scrubJulian;
- evt.clock = this._clock;
- this._topDiv.dispatchEvent(evt);
- };
- function createMouseDownCallback(timeline) {
- return function(e) {
- if (timeline._mouseMode !== timelineMouseMode.touchOnly) {
- if (e.button === 0) {
- timeline._mouseMode = timelineMouseMode.scrub;
- if (timeline._scrubElement) {
- timeline._scrubElement.style.backgroundPosition = '-16px 0';
- }
- timeline._onMouseMove(e);
- } else {
- timeline._mouseX = e.clientX;
- if (e.button === 2) {
- timeline._mouseMode = timelineMouseMode.zoom;
- } else {
- timeline._mouseMode = timelineMouseMode.slide;
- }
- }
- }
- e.preventDefault();
- };
- }
- function createMouseUpCallback(timeline) {
- return function(e) {
- timeline._mouseMode = timelineMouseMode.none;
- if (timeline._scrubElement) {
- timeline._scrubElement.style.backgroundPosition = '0px 0px';
- }
- timeline._timelineDrag = 0;
- timeline._timelineDragLocation = undefined;
- };
- }
- function createMouseMoveCallback(timeline) {
- return function(e) {
- var dx;
- if (timeline._mouseMode === timelineMouseMode.scrub) {
- e.preventDefault();
- var x = e.clientX - timeline._topDiv.getBoundingClientRect().left;
- if (x < 0) {
- timeline._timelineDragLocation = 0;
- timeline._timelineDrag = -0.01 * timeline._timeBarSecondsSpan;
- } else if (x > timeline._topDiv.clientWidth) {
- timeline._timelineDragLocation = timeline._topDiv.clientWidth;
- timeline._timelineDrag = 0.01 * timeline._timeBarSecondsSpan;
- } else {
- timeline._timelineDragLocation = undefined;
- timeline._setTimeBarTime(x, x * timeline._timeBarSecondsSpan / timeline._topDiv.clientWidth);
- }
- } else if (timeline._mouseMode === timelineMouseMode.slide) {
- dx = timeline._mouseX - e.clientX;
- timeline._mouseX = e.clientX;
- if (dx !== 0) {
- var dsec = dx * timeline._timeBarSecondsSpan / timeline._topDiv.clientWidth;
- timeline.zoomTo(JulianDate.addSeconds(timeline._startJulian, dsec, new JulianDate()), JulianDate.addSeconds(timeline._endJulian, dsec, new JulianDate()));
- }
- } else if (timeline._mouseMode === timelineMouseMode.zoom) {
- dx = timeline._mouseX - e.clientX;
- timeline._mouseX = e.clientX;
- if (dx !== 0) {
- timeline.zoomFrom(Math.pow(1.01, dx));
- }
- }
- };
- }
- function createMouseWheelCallback(timeline) {
- return function(e) {
- var dy = e.wheelDeltaY || e.wheelDelta || (-e.detail);
- timelineWheelDelta = Math.max(Math.min(Math.abs(dy), timelineWheelDelta), 1);
- dy /= timelineWheelDelta;
- timeline.zoomFrom(Math.pow(1.05, -dy));
- };
- }
- function createTouchStartCallback(timeline) {
- return function(e) {
- var len = e.touches.length, seconds, xPos, leftX = timeline._topDiv.getBoundingClientRect().left;
- e.preventDefault();
- timeline._mouseMode = timelineMouseMode.touchOnly;
- if (len === 1) {
- seconds = JulianDate.secondsDifference(timeline._scrubJulian, timeline._startJulian);
- xPos = Math.round(seconds * timeline._topDiv.clientWidth / timeline._timeBarSecondsSpan + leftX);
- if (Math.abs(e.touches[0].clientX - xPos) < 50) {
- timeline._touchMode = timelineTouchMode.scrub;
- if (timeline._scrubElement) {
- timeline._scrubElement.style.backgroundPosition = (len === 1) ? '-16px 0' : '0 0';
- }
- } else {
- timeline._touchMode = timelineTouchMode.singleTap;
- timeline._touchState.centerX = e.touches[0].clientX - leftX;
- }
- } else if (len === 2) {
- timeline._touchMode = timelineTouchMode.slideZoom;
- timeline._touchState.centerX = (e.touches[0].clientX + e.touches[1].clientX) * 0.5 - leftX;
- timeline._touchState.spanX = Math.abs(e.touches[0].clientX - e.touches[1].clientX);
- } else {
- timeline._touchMode = timelineTouchMode.ignore;
- }
- };
- }
- function createTouchEndCallback(timeline) {
- return function(e) {
- var len = e.touches.length, leftX = timeline._topDiv.getBoundingClientRect().left;
- if (timeline._touchMode === timelineTouchMode.singleTap) {
- timeline._touchMode = timelineTouchMode.scrub;
- timeline._handleTouchMove(e);
- } else if (timeline._touchMode === timelineTouchMode.scrub) {
- timeline._handleTouchMove(e);
- }
- timeline._mouseMode = timelineMouseMode.touchOnly;
- if (len !== 1) {
- timeline._touchMode = (len > 0) ? timelineTouchMode.ignore : timelineTouchMode.none;
- } else if (timeline._touchMode === timelineTouchMode.slideZoom) {
- timeline._touchState.centerX = e.touches[0].clientX - leftX;
- }
- if (timeline._scrubElement) {
- timeline._scrubElement.style.backgroundPosition = '0 0';
- }
- };
- }
- function createTouchMoveCallback(timeline) {
- return function(e) {
- var dx, x, len, newCenter, newSpan, newStartTime, zoom = 1, leftX = timeline._topDiv.getBoundingClientRect().left;
- if (timeline._touchMode === timelineTouchMode.singleTap) {
- timeline._touchMode = timelineTouchMode.slideZoom;
- }
- timeline._mouseMode = timelineMouseMode.touchOnly;
- if (timeline._touchMode === timelineTouchMode.scrub) {
- e.preventDefault();
- if (e.changedTouches.length === 1) {
- x = e.changedTouches[0].clientX - leftX;
- if ((x >= 0) && (x <= timeline._topDiv.clientWidth)) {
- timeline._setTimeBarTime(x, x * timeline._timeBarSecondsSpan / timeline._topDiv.clientWidth);
- }
- }
- } else if (timeline._touchMode === timelineTouchMode.slideZoom) {
- len = e.touches.length;
- if (len === 2) {
- newCenter = (e.touches[0].clientX + e.touches[1].clientX) * 0.5 - leftX;
- newSpan = Math.abs(e.touches[0].clientX - e.touches[1].clientX);
- } else if (len === 1) {
- newCenter = e.touches[0].clientX - leftX;
- newSpan = 0;
- }
- if (defined(newCenter)) {
- if ((newSpan > 0) && (timeline._touchState.spanX > 0)) {
- // Zoom and slide
- zoom = (timeline._touchState.spanX / newSpan);
- newStartTime = JulianDate.addSeconds(timeline._startJulian, ((timeline._touchState.centerX * timeline._timeBarSecondsSpan) - (newCenter * timeline._timeBarSecondsSpan * zoom)) / timeline._topDiv.clientWidth, new JulianDate());
- } else {
- // Slide to newCenter
- dx = timeline._touchState.centerX - newCenter;
- newStartTime = JulianDate.addSeconds(timeline._startJulian, dx * timeline._timeBarSecondsSpan / timeline._topDiv.clientWidth, new JulianDate());
- }
- timeline.zoomTo(newStartTime, JulianDate.addSeconds(newStartTime, timeline._timeBarSecondsSpan * zoom, new JulianDate()));
- timeline._touchState.centerX = newCenter;
- timeline._touchState.spanX = newSpan;
- }
- }
- };
- }
- /**
- * Resizes the widget to match the container size.
- */
- Timeline.prototype.resize = function() {
- var width = this.container.clientWidth;
- var height = this.container.clientHeight;
- if (width === this._lastWidth && height === this._lastHeight) {
- return;
- }
- this._trackContainer.style.height = height + 'px';
- var trackListHeight = 1;
- this._trackList.forEach(function(track) {
- trackListHeight += track.height;
- });
- this._trackListEle.style.height = trackListHeight.toString() + 'px';
- this._trackListEle.width = this._trackListEle.clientWidth;
- this._trackListEle.height = trackListHeight;
- this._makeTics();
- this._lastWidth = width;
- this._lastHeight = height;
- };
- return Timeline;
- });
|