Added: openoffice/ooo-site/trunk/content/scripts/simile-widget/timeline/2.3.1/scripts/band.js URL: http://svn.apache.org/viewvc/openoffice/ooo-site/trunk/content/scripts/simile-widget/timeline/2.3.1/scripts/band.js?rev=1791126&view=auto ============================================================================== --- openoffice/ooo-site/trunk/content/scripts/simile-widget/timeline/2.3.1/scripts/band.js (added) +++ openoffice/ooo-site/trunk/content/scripts/simile-widget/timeline/2.3.1/scripts/band.js Wed Apr 12 14:36:37 2017 @@ -0,0 +1,733 @@ +/*================================================= + * + * Coding standards: + * + * We aim towards Douglas Crockford's Javascript conventions. + * See: http://javascript.crockford.com/code.html + * See also: http://www.crockford.com/javascript/javascript.html + * + * That said, this JS code was written before some recent JS + * support libraries became widely used or available. + * In particular, the _ character is used to indicate a class function or + * variable that should be considered private to the class. + * + * The code mostly uses accessor methods for getting/setting the private + * class variables. + * + * Over time, we'd like to formalize the convention by using support libraries + * which enforce privacy in objects. + * + * We also want to use jslint: http://www.jslint.com/ + * + * + *================================================== + */ + + + +/*================================================== + * Band + *================================================== + */ +Timeline._Band = function(timeline, bandInfo, index) { + // Set up the band's object + + // Munge params: If autoWidth is on for the Timeline, then ensure that + // bandInfo.width is an integer + if (timeline.autoWidth && typeof bandInfo.width == 'string') { + bandInfo.width = bandInfo.width.indexOf("%") > -1 ? 0 : parseInt(bandInfo.width); + } + + this._timeline = timeline; + this._bandInfo = bandInfo; + + this._index = index; + + this._locale = ("locale" in bandInfo) ? bandInfo.locale : Timeline.getDefaultLocale(); + this._timeZone = ("timeZone" in bandInfo) ? bandInfo.timeZone : 0; + this._labeller = ("labeller" in bandInfo) ? bandInfo.labeller : + (("createLabeller" in timeline.getUnit()) ? + timeline.getUnit().createLabeller(this._locale, this._timeZone) : + new Timeline.GregorianDateLabeller(this._locale, this._timeZone)); + this._theme = bandInfo.theme; + this._zoomIndex = ("zoomIndex" in bandInfo) ? bandInfo.zoomIndex : 0; + this._zoomSteps = ("zoomSteps" in bandInfo) ? bandInfo.zoomSteps : null; + + this._dragging = false; + this._changing = false; + this._originalScrollSpeed = 5; // pixels + this._scrollSpeed = this._originalScrollSpeed; + this._onScrollListeners = []; + + var b = this; + this._syncWithBand = null; + this._syncWithBandHandler = function(band) { + b._onHighlightBandScroll(); + }; + this._selectorListener = function(band) { + b._onHighlightBandScroll(); + }; + + /* + * Install a textbox to capture keyboard events + */ + var inputDiv = this._timeline.getDocument().createElement("div"); + inputDiv.className = "timeline-band-input"; + this._timeline.addDiv(inputDiv); + + this._keyboardInput = document.createElement("input"); + this._keyboardInput.type = "text"; + inputDiv.appendChild(this._keyboardInput); + SimileAjax.DOM.registerEventWithObject(this._keyboardInput, "keydown", this, "_onKeyDown"); + SimileAjax.DOM.registerEventWithObject(this._keyboardInput, "keyup", this, "_onKeyUp"); + + /* + * The band's outer most div that slides with respect to the timeline's div + */ + this._div = this._timeline.getDocument().createElement("div"); + this._div.id = "timeline-band-" + index; + this._div.className = "timeline-band timeline-band-" + index; + this._timeline.addDiv(this._div); + + SimileAjax.DOM.registerEventWithObject(this._div, "mousedown", this, "_onMouseDown"); + SimileAjax.DOM.registerEventWithObject(this._div, "mousemove", this, "_onMouseMove"); + SimileAjax.DOM.registerEventWithObject(this._div, "mouseup", this, "_onMouseUp"); + SimileAjax.DOM.registerEventWithObject(this._div, "mouseout", this, "_onMouseOut"); + SimileAjax.DOM.registerEventWithObject(this._div, "dblclick", this, "_onDblClick"); + + var mouseWheel = this._theme!= null ? this._theme.mouseWheel : 'scroll'; // theme is not always defined + if (mouseWheel === 'zoom' || mouseWheel === 'scroll' || this._zoomSteps) { + // capture mouse scroll + if (SimileAjax.Platform.browser.isFirefox) { + SimileAjax.DOM.registerEventWithObject(this._div, "DOMMouseScroll", this, "_onMouseScroll"); + } else { + SimileAjax.DOM.registerEventWithObject(this._div, "mousewheel", this, "_onMouseScroll"); + } + } + + /* + * The inner div that contains layers + */ + this._innerDiv = this._timeline.getDocument().createElement("div"); + this._innerDiv.className = "timeline-band-inner"; + this._div.appendChild(this._innerDiv); + + /* + * Initialize parts of the band + */ + this._ether = bandInfo.ether; + bandInfo.ether.initialize(this, timeline); + + this._etherPainter = bandInfo.etherPainter; + bandInfo.etherPainter.initialize(this, timeline); + + this._eventSource = bandInfo.eventSource; + if (this._eventSource) { + this._eventListener = { + onAddMany: function() { b._onAddMany(); }, + onClear: function() { b._onClear(); } + } + this._eventSource.addListener(this._eventListener); + } + + this._eventPainter = bandInfo.eventPainter; + this._eventTracksNeeded = 0; // set by painter via updateEventTrackInfo + this._eventTrackIncrement = 0; + bandInfo.eventPainter.initialize(this, timeline); + + this._decorators = ("decorators" in bandInfo) ? bandInfo.decorators : []; + for (var i = 0; i < this._decorators.length; i++) { + this._decorators[i].initialize(this, timeline); + } +}; + +Timeline._Band.SCROLL_MULTIPLES = 5; + +Timeline._Band.prototype.dispose = function() { + this.closeBubble(); + + if (this._eventSource) { + this._eventSource.removeListener(this._eventListener); + this._eventListener = null; + this._eventSource = null; + } + + this._timeline = null; + this._bandInfo = null; + + this._labeller = null; + this._ether = null; + this._etherPainter = null; + this._eventPainter = null; + this._decorators = null; + + this._onScrollListeners = null; + this._syncWithBandHandler = null; + this._selectorListener = null; + + this._div = null; + this._innerDiv = null; + this._keyboardInput = null; +}; + +Timeline._Band.prototype.addOnScrollListener = function(listener) { + this._onScrollListeners.push(listener); +}; + +Timeline._Band.prototype.removeOnScrollListener = function(listener) { + for (var i = 0; i < this._onScrollListeners.length; i++) { + if (this._onScrollListeners[i] == listener) { + this._onScrollListeners.splice(i, 1); + break; + } + } +}; + +Timeline._Band.prototype.setSyncWithBand = function(band, highlight) { + if (this._syncWithBand) { + this._syncWithBand.removeOnScrollListener(this._syncWithBandHandler); + } + + this._syncWithBand = band; + this._syncWithBand.addOnScrollListener(this._syncWithBandHandler); + this._highlight = highlight; + this._positionHighlight(); +}; + +Timeline._Band.prototype.getLocale = function() { + return this._locale; +}; + +Timeline._Band.prototype.getTimeZone = function() { + return this._timeZone; +}; + +Timeline._Band.prototype.getLabeller = function() { + return this._labeller; +}; + +Timeline._Band.prototype.getIndex = function() { + return this._index; +}; + +Timeline._Band.prototype.getEther = function() { + return this._ether; +}; + +Timeline._Band.prototype.getEtherPainter = function() { + return this._etherPainter; +}; + +Timeline._Band.prototype.getEventSource = function() { + return this._eventSource; +}; + +Timeline._Band.prototype.getEventPainter = function() { + return this._eventPainter; +}; + +Timeline._Band.prototype.getTimeline = function() { + return this._timeline; +}; + +// Autowidth support +Timeline._Band.prototype.updateEventTrackInfo = function(tracks, increment) { + this._eventTrackIncrement = increment; // doesn't vary for a specific band + + if (tracks > this._eventTracksNeeded) { + this._eventTracksNeeded = tracks; + } +}; + +// Autowidth support +Timeline._Band.prototype.checkAutoWidth = function() { + // if a new (larger) width is needed by the band + // then: a) updates the band's bandInfo.width + // + // desiredWidth for the band is + // (number of tracks + margin) * track increment + if (! this._timeline.autoWidth) { + return; // early return + } + + var overviewBand = this._eventPainter.getType() == 'overview'; + var margin = overviewBand ? + this._theme.event.overviewTrack.autoWidthMargin : + this._theme.event.track.autoWidthMargin; + var desiredWidth = Math.ceil((this._eventTracksNeeded + margin) * + this._eventTrackIncrement); + // add offset amount (additional margin) + desiredWidth += overviewBand ? this._theme.event.overviewTrack.offset : + this._theme.event.track.offset; + var bandInfo = this._bandInfo; + + if (desiredWidth != bandInfo.width) { + bandInfo.width = desiredWidth; + } +}; + +Timeline._Band.prototype.layout = function() { + this.paint(); +}; + +Timeline._Band.prototype.paint = function() { + this._etherPainter.paint(); + this._paintDecorators(); + this._paintEvents(); +}; + +Timeline._Band.prototype.softLayout = function() { + this.softPaint(); +}; + +Timeline._Band.prototype.softPaint = function() { + this._etherPainter.softPaint(); + this._softPaintDecorators(); + this._softPaintEvents(); +}; + +Timeline._Band.prototype.setBandShiftAndWidth = function(shift, width) { + var inputDiv = this._keyboardInput.parentNode; + var middle = shift + Math.floor(width / 2); + if (this._timeline.isHorizontal()) { + this._div.style.top = shift + "px"; + this._div.style.height = width + "px"; + + inputDiv.style.top = middle + "px"; + inputDiv.style.left = "-1em"; + } else { + this._div.style.left = shift + "px"; + this._div.style.width = width + "px"; + + inputDiv.style.left = middle + "px"; + inputDiv.style.top = "-1em"; + } +}; + +Timeline._Band.prototype.getViewWidth = function() { + if (this._timeline.isHorizontal()) { + return this._div.offsetHeight; + } else { + return this._div.offsetWidth; + } +}; + +Timeline._Band.prototype.setViewLength = function(length) { + this._viewLength = length; + this._recenterDiv(); + this._onChanging(); +}; + +Timeline._Band.prototype.getViewLength = function() { + return this._viewLength; +}; + +Timeline._Band.prototype.getTotalViewLength = function() { + return Timeline._Band.SCROLL_MULTIPLES * this._viewLength; +}; + +Timeline._Band.prototype.getViewOffset = function() { + return this._viewOffset; +}; + +Timeline._Band.prototype.getMinDate = function() { + return this._ether.pixelOffsetToDate(this._viewOffset); +}; + +Timeline._Band.prototype.getMaxDate = function() { + return this._ether.pixelOffsetToDate(this._viewOffset + Timeline._Band.SCROLL_MULTIPLES * this._viewLength); +}; + +Timeline._Band.prototype.getMinVisibleDate = function() { + return this._ether.pixelOffsetToDate(0); +}; + +Timeline._Band.prototype.getMinVisibleDateAfterDelta = function(delta) { + return this._ether.pixelOffsetToDate(delta); +}; + +Timeline._Band.prototype.getMaxVisibleDate = function() { + // Max date currently visible on band + return this._ether.pixelOffsetToDate(this._viewLength); +}; + +Timeline._Band.prototype.getMaxVisibleDateAfterDelta = function(delta) { + // Max date visible on band after delta px view change is applied + return this._ether.pixelOffsetToDate(this._viewLength + delta); +}; + +Timeline._Band.prototype.getCenterVisibleDate = function() { + return this._ether.pixelOffsetToDate(this._viewLength / 2); +}; + +Timeline._Band.prototype.setMinVisibleDate = function(date) { + if (!this._changing) { + this._moveEther(Math.round(-this._ether.dateToPixelOffset(date))); + } +}; + +Timeline._Band.prototype.setMaxVisibleDate = function(date) { + if (!this._changing) { + this._moveEther(Math.round(this._viewLength - this._ether.dateToPixelOffset(date))); + } +}; + +Timeline._Band.prototype.setCenterVisibleDate = function(date) { + if (!this._changing) { + this._moveEther(Math.round(this._viewLength / 2 - this._ether.dateToPixelOffset(date))); + } +}; + +Timeline._Band.prototype.dateToPixelOffset = function(date) { + return this._ether.dateToPixelOffset(date) - this._viewOffset; +}; + +Timeline._Band.prototype.pixelOffsetToDate = function(pixels) { + return this._ether.pixelOffsetToDate(pixels + this._viewOffset); +}; + +Timeline._Band.prototype.createLayerDiv = function(zIndex, className) { + var div = this._timeline.getDocument().createElement("div"); + div.className = "timeline-band-layer" + (typeof className == "string" ? (" " + className) : ""); + div.style.zIndex = zIndex; + this._innerDiv.appendChild(div); + + var innerDiv = this._timeline.getDocument().createElement("div"); + innerDiv.className = "timeline-band-layer-inner"; + if (SimileAjax.Platform.browser.isIE) { + innerDiv.style.cursor = "move"; + } else { + innerDiv.style.cursor = "-moz-grab"; + } + div.appendChild(innerDiv); + + return innerDiv; +}; + +Timeline._Band.prototype.removeLayerDiv = function(div) { + this._innerDiv.removeChild(div.parentNode); +}; + +Timeline._Band.prototype.scrollToCenter = function(date, f) { + var pixelOffset = this._ether.dateToPixelOffset(date); + if (pixelOffset < -this._viewLength / 2) { + this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset + this._viewLength)); + } else if (pixelOffset > 3 * this._viewLength / 2) { + this.setCenterVisibleDate(this.pixelOffsetToDate(pixelOffset - this._viewLength)); + } + this._autoScroll(Math.round(this._viewLength / 2 - this._ether.dateToPixelOffset(date)), f); +}; + +Timeline._Band.prototype.showBubbleForEvent = function(eventID) { + var evt = this.getEventSource().getEvent(eventID); + if (evt) { + var self = this; + this.scrollToCenter(evt.getStart(), function() { + self._eventPainter.showBubble(evt); + }); + } +}; + +Timeline._Band.prototype.zoom = function(zoomIn, x, y, target) { + if (!this._zoomSteps) { + // zoom disabled + return; + } + + // shift the x value by our offset + x += this._viewOffset; + + var zoomDate = this._ether.pixelOffsetToDate(x); + var netIntervalChange = this._ether.zoom(zoomIn); + this._etherPainter.zoom(netIntervalChange); + + // shift our zoom date to the far left + this._moveEther(Math.round(-this._ether.dateToPixelOffset(zoomDate))); + // then shift it back to where the mouse was + this._moveEther(x); +}; + +Timeline._Band.prototype._onMouseDown = function(innerFrame, evt, target) { + this.closeBubble(); + + this._dragging = true; + this._dragX = evt.clientX; + this._dragY = evt.clientY; +}; + +Timeline._Band.prototype._onMouseMove = function(innerFrame, evt, target) { + if (this._dragging) { + var diffX = evt.clientX - this._dragX; + var diffY = evt.clientY - this._dragY; + + this._dragX = evt.clientX; + this._dragY = evt.clientY; + + this._moveEther(this._timeline.isHorizontal() ? diffX : diffY); + this._positionHighlight(); + } +}; + +Timeline._Band.prototype._onMouseUp = function(innerFrame, evt, target) { + this._dragging = false; + this._keyboardInput.focus(); +}; + +Timeline._Band.prototype._onMouseOut = function(innerFrame, evt, target) { + var coords = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame); + coords.x += this._viewOffset; + if (coords.x < 0 || coords.x > innerFrame.offsetWidth || + coords.y < 0 || coords.y > innerFrame.offsetHeight) { + this._dragging = false; + } +}; + +Timeline._Band.prototype._onMouseScroll = function(innerFrame, evt, target) { + var now = new Date(); + now = now.getTime(); + + if (!this._lastScrollTime || ((now - this._lastScrollTime) > 50)) { + // limit 1 scroll per 200ms due to FF3 sending multiple events back to back + this._lastScrollTime = now; + + var delta = 0; + if (evt.wheelDelta) { + delta = evt.wheelDelta/120; + } else if (evt.detail) { + delta = -evt.detail/3; + } + + // either scroll or zoom + var mouseWheel = this._theme.mouseWheel; + + if (this._zoomSteps || mouseWheel === 'zoom') { + var loc = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame); + if (delta != 0) { + var zoomIn; + if (delta > 0) + zoomIn = true; + if (delta < 0) + zoomIn = false; + // call zoom on the timeline so we could zoom multiple bands if desired + this._timeline.zoom(zoomIn, loc.x, loc.y, innerFrame); + } + } + else if (mouseWheel === 'scroll') { + var move_amt = 50 * (delta < 0 ? -1 : 1); + this._moveEther(move_amt); + } + } + + // prevent bubble + if (evt.stopPropagation) { + evt.stopPropagation(); + } + evt.cancelBubble = true; + + // prevent the default action + if (evt.preventDefault) { + evt.preventDefault(); + } + evt.returnValue = false; +}; + +Timeline._Band.prototype._onDblClick = function(innerFrame, evt, target) { + var coords = SimileAjax.DOM.getEventRelativeCoordinates(evt, innerFrame); + var distance = coords.x - (this._viewLength / 2 - this._viewOffset); + + this._autoScroll(-distance); +}; + +Timeline._Band.prototype._onKeyDown = function(keyboardInput, evt, target) { + if (!this._dragging) { + switch (evt.keyCode) { + case 27: // ESC + break; + case 37: // left arrow + case 38: // up arrow + this._scrollSpeed = Math.min(50, Math.abs(this._scrollSpeed * 1.05)); + this._moveEther(this._scrollSpeed); + break; + case 39: // right arrow + case 40: // down arrow + this._scrollSpeed = -Math.min(50, Math.abs(this._scrollSpeed * 1.05)); + this._moveEther(this._scrollSpeed); + break; + default: + return true; + } + this.closeBubble(); + + SimileAjax.DOM.cancelEvent(evt); + return false; + } + return true; +}; + +Timeline._Band.prototype._onKeyUp = function(keyboardInput, evt, target) { + if (!this._dragging) { + this._scrollSpeed = this._originalScrollSpeed; + + switch (evt.keyCode) { + case 35: // end + this.setCenterVisibleDate(this._eventSource.getLatestDate()); + break; + case 36: // home + this.setCenterVisibleDate(this._eventSource.getEarliestDate()); + break; + case 33: // page up + this._autoScroll(this._timeline.getPixelLength()); + break; + case 34: // page down + this._autoScroll(-this._timeline.getPixelLength()); + break; + default: + return true; + } + + this.closeBubble(); + + SimileAjax.DOM.cancelEvent(evt); + return false; + } + return true; +}; + +Timeline._Band.prototype._autoScroll = function(distance, f) { + var b = this; + var a = SimileAjax.Graphics.createAnimation( + function(abs, diff) { + b._moveEther(diff); + }, + 0, + distance, + 1000, + f + ); + a.run(); +}; + +Timeline._Band.prototype._moveEther = function(shift) { + this.closeBubble(); + + // A positive shift means back in time + // Check that we're not moving beyond Timeline's limits + if (!this._timeline.shiftOK(this._index, shift)) { + return; // early return + } + + this._viewOffset += shift; + this._ether.shiftPixels(-shift); + if (this._timeline.isHorizontal()) { + this._div.style.left = this._viewOffset + "px"; + } else { + this._div.style.top = this._viewOffset + "px"; + } + + if (this._viewOffset > -this._viewLength * 0.5 || + this._viewOffset < -this._viewLength * (Timeline._Band.SCROLL_MULTIPLES - 1.5)) { + + this._recenterDiv(); + } else { + this.softLayout(); + } + + this._onChanging(); +} + +Timeline._Band.prototype._onChanging = function() { + this._changing = true; + + this._fireOnScroll(); + this._setSyncWithBandDate(); + + this._changing = false; +}; + +Timeline._Band.prototype.busy = function() { + // Is this band busy changing other bands? + return(this._changing); +}; + +Timeline._Band.prototype._fireOnScroll = function() { + for (var i = 0; i < this._onScrollListeners.length; i++) { + this._onScrollListeners[i](this); + } +}; + +Timeline._Band.prototype._setSyncWithBandDate = function() { + if (this._syncWithBand) { + var centerDate = this._ether.pixelOffsetToDate(this.getViewLength() / 2); + this._syncWithBand.setCenterVisibleDate(centerDate); + } +}; + +Timeline._Band.prototype._onHighlightBandScroll = function() { + if (this._syncWithBand) { + var centerDate = this._syncWithBand.getCenterVisibleDate(); + var centerPixelOffset = this._ether.dateToPixelOffset(centerDate); + + this._moveEther(Math.round(this._viewLength / 2 - centerPixelOffset)); + + if (this._highlight) { + this._etherPainter.setHighlight( + this._syncWithBand.getMinVisibleDate(), + this._syncWithBand.getMaxVisibleDate()); + } + } +}; + +Timeline._Band.prototype._onAddMany = function() { + this._paintEvents(); +}; + +Timeline._Band.prototype._onClear = function() { + this._paintEvents(); +}; + +Timeline._Band.prototype._positionHighlight = function() { + if (this._syncWithBand) { + var startDate = this._syncWithBand.getMinVisibleDate(); + var endDate = this._syncWithBand.getMaxVisibleDate(); + + if (this._highlight) { + this._etherPainter.setHighlight(startDate, endDate); + } + } +}; + +Timeline._Band.prototype._recenterDiv = function() { + this._viewOffset = -this._viewLength * (Timeline._Band.SCROLL_MULTIPLES - 1) / 2; + if (this._timeline.isHorizontal()) { + this._div.style.left = this._viewOffset + "px"; + this._div.style.width = (Timeline._Band.SCROLL_MULTIPLES * this._viewLength) + "px"; + } else { + this._div.style.top = this._viewOffset + "px"; + this._div.style.height = (Timeline._Band.SCROLL_MULTIPLES * this._viewLength) + "px"; + } + this.layout(); +}; + +Timeline._Band.prototype._paintEvents = function() { + this._eventPainter.paint(); +}; + +Timeline._Band.prototype._softPaintEvents = function() { + this._eventPainter.softPaint(); +}; + +Timeline._Band.prototype._paintDecorators = function() { + for (var i = 0; i < this._decorators.length; i++) { + this._decorators[i].paint(); + } +}; + +Timeline._Band.prototype._softPaintDecorators = function() { + for (var i = 0; i < this._decorators.length; i++) { + this._decorators[i].softPaint(); + } +}; + +Timeline._Band.prototype.closeBubble = function() { + SimileAjax.WindowManager.cancelPopups(); +};
Added: openoffice/ooo-site/trunk/content/scripts/simile-widget/timeline/2.3.1/scripts/compact-painter.js URL: http://svn.apache.org/viewvc/openoffice/ooo-site/trunk/content/scripts/simile-widget/timeline/2.3.1/scripts/compact-painter.js?rev=1791126&view=auto ============================================================================== --- openoffice/ooo-site/trunk/content/scripts/simile-widget/timeline/2.3.1/scripts/compact-painter.js (added) +++ openoffice/ooo-site/trunk/content/scripts/simile-widget/timeline/2.3.1/scripts/compact-painter.js Wed Apr 12 14:36:37 2017 @@ -0,0 +1,1041 @@ +/*================================================== + * Original Event Painter + *================================================== + */ + +Timeline.CompactEventPainter = function(params) { + this._params = params; + this._onSelectListeners = []; + + this._filterMatcher = null; + this._highlightMatcher = null; + this._frc = null; + + this._eventIdToElmt = {}; +}; + +Timeline.CompactEventPainter.prototype.initialize = function(band, timeline) { + this._band = band; + this._timeline = timeline; + + this._backLayer = null; + this._eventLayer = null; + this._lineLayer = null; + this._highlightLayer = null; + + this._eventIdToElmt = null; +}; + +Timeline.CompactEventPainter.prototype.addOnSelectListener = function(listener) { + this._onSelectListeners.push(listener); +}; + +Timeline.CompactEventPainter.prototype.removeOnSelectListener = function(listener) { + for (var i = 0; i < this._onSelectListeners.length; i++) { + if (this._onSelectListeners[i] == listener) { + this._onSelectListeners.splice(i, 1); + break; + } + } +}; + +Timeline.CompactEventPainter.prototype.getFilterMatcher = function() { + return this._filterMatcher; +}; + +Timeline.CompactEventPainter.prototype.setFilterMatcher = function(filterMatcher) { + this._filterMatcher = filterMatcher; +}; + +Timeline.CompactEventPainter.prototype.getHighlightMatcher = function() { + return this._highlightMatcher; +}; + +Timeline.CompactEventPainter.prototype.setHighlightMatcher = function(highlightMatcher) { + this._highlightMatcher = highlightMatcher; +}; + +Timeline.CompactEventPainter.prototype.paint = function() { + var eventSource = this._band.getEventSource(); + if (eventSource == null) { + return; + } + + this._eventIdToElmt = {}; + this._prepareForPainting(); + + var theme = this._params.theme; + var eventTheme = theme.event; + + var metrics = { + trackOffset: "trackOffset" in this._params ? this._params.trackOffset : 10, + trackHeight: "trackHeight" in this._params ? this._params.trackHeight : 10, + + tapeHeight: theme.event.tape.height, + tapeBottomMargin: "tapeBottomMargin" in this._params ? this._params.tapeBottomMargin : 2, + + labelBottomMargin: "labelBottomMargin" in this._params ? this._params.labelBottomMargin : 5, + labelRightMargin: "labelRightMargin" in this._params ? this._params.labelRightMargin : 5, + + defaultIcon: eventTheme.instant.icon, + defaultIconWidth: eventTheme.instant.iconWidth, + defaultIconHeight: eventTheme.instant.iconHeight, + + customIconWidth: "iconWidth" in this._params ? this._params.iconWidth : eventTheme.instant.iconWidth, + customIconHeight: "iconHeight" in this._params ? this._params.iconHeight : eventTheme.instant.iconHeight, + + iconLabelGap: "iconLabelGap" in this._params ? this._params.iconLabelGap : 2, + iconBottomMargin: "iconBottomMargin" in this._params ? this._params.iconBottomMargin : 2 + }; + if ("compositeIcon" in this._params) { + metrics.compositeIcon = this._params.compositeIcon; + metrics.compositeIconWidth = this._params.compositeIconWidth || metrics.customIconWidth; + metrics.compositeIconHeight = this._params.compositeIconHeight || metrics.customIconHeight; + } else { + metrics.compositeIcon = metrics.defaultIcon; + metrics.compositeIconWidth = metrics.defaultIconWidth; + metrics.compositeIconHeight = metrics.defaultIconHeight; + } + metrics.defaultStackIcon = "icon" in this._params.stackConcurrentPreciseInstantEvents ? + this._params.stackConcurrentPreciseInstantEvents.icon : metrics.defaultIcon; + metrics.defaultStackIconWidth = "iconWidth" in this._params.stackConcurrentPreciseInstantEvents ? + this._params.stackConcurrentPreciseInstantEvents.iconWidth : metrics.defaultIconWidth; + metrics.defaultStackIconHeight = "iconHeight" in this._params.stackConcurrentPreciseInstantEvents ? + this._params.stackConcurrentPreciseInstantEvents.iconHeight : metrics.defaultIconHeight; + + var minDate = this._band.getMinDate(); + var maxDate = this._band.getMaxDate(); + + var filterMatcher = (this._filterMatcher != null) ? + this._filterMatcher : + function(evt) { return true; }; + + var highlightMatcher = (this._highlightMatcher != null) ? + this._highlightMatcher : + function(evt) { return -1; }; + + var iterator = eventSource.getEventIterator(minDate, maxDate); + + var stackConcurrentPreciseInstantEvents = "stackConcurrentPreciseInstantEvents" in this._params && typeof this._params.stackConcurrentPreciseInstantEvents == "object"; + var collapseConcurrentPreciseInstantEvents = "collapseConcurrentPreciseInstantEvents" in this._params && this._params.collapseConcurrentPreciseInstantEvents; + if (collapseConcurrentPreciseInstantEvents || stackConcurrentPreciseInstantEvents) { + var bufferedEvents = []; + var previousInstantEvent = null; + + while (iterator.hasNext()) { + var evt = iterator.next(); + if (filterMatcher(evt)) { + if (!evt.isInstant() || evt.isImprecise()) { + this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt)); + } else if (previousInstantEvent != null && + previousInstantEvent.getStart().getTime() == evt.getStart().getTime()) { + bufferedEvents[bufferedEvents.length - 1].push(evt); + } else { + bufferedEvents.push([ evt ]); + previousInstantEvent = evt; + } + } + } + + for (var i = 0; i < bufferedEvents.length; i++) { + var compositeEvents = bufferedEvents[i]; + if (compositeEvents.length == 1) { + this.paintEvent(compositeEvents[0], metrics, this._params.theme, highlightMatcher(evt)); + } else { + var match = -1; + for (var j = 0; match < 0 && j < compositeEvents.length; j++) { + match = highlightMatcher(compositeEvents[j]); + } + + if (stackConcurrentPreciseInstantEvents) { + this.paintStackedPreciseInstantEvents(compositeEvents, metrics, this._params.theme, match); + } else { + this.paintCompositePreciseInstantEvents(compositeEvents, metrics, this._params.theme, match); + } + } + } + } else { + while (iterator.hasNext()) { + var evt = iterator.next(); + if (filterMatcher(evt)) { + this.paintEvent(evt, metrics, this._params.theme, highlightMatcher(evt)); + } + } + } + + this._highlightLayer.style.display = "block"; + this._lineLayer.style.display = "block"; + this._eventLayer.style.display = "block"; +}; + +Timeline.CompactEventPainter.prototype.softPaint = function() { +}; + +Timeline.CompactEventPainter.prototype._prepareForPainting = function() { + var band = this._band; + + if (this._backLayer == null) { + this._backLayer = this._band.createLayerDiv(0, "timeline-band-events"); + this._backLayer.style.visibility = "hidden"; + + var eventLabelPrototype = document.createElement("span"); + eventLabelPrototype.className = "timeline-event-label"; + this._backLayer.appendChild(eventLabelPrototype); + this._frc = SimileAjax.Graphics.getFontRenderingContext(eventLabelPrototype); + } + this._frc.update(); + this._tracks = []; + + if (this._highlightLayer != null) { + band.removeLayerDiv(this._highlightLayer); + } + this._highlightLayer = band.createLayerDiv(105, "timeline-band-highlights"); + this._highlightLayer.style.display = "none"; + + if (this._lineLayer != null) { + band.removeLayerDiv(this._lineLayer); + } + this._lineLayer = band.createLayerDiv(110, "timeline-band-lines"); + this._lineLayer.style.display = "none"; + + if (this._eventLayer != null) { + band.removeLayerDiv(this._eventLayer); + } + this._eventLayer = band.createLayerDiv(115, "timeline-band-events"); + this._eventLayer.style.display = "none"; +}; + +Timeline.CompactEventPainter.prototype.paintEvent = function(evt, metrics, theme, highlightIndex) { + if (evt.isInstant()) { + this.paintInstantEvent(evt, metrics, theme, highlightIndex); + } else { + this.paintDurationEvent(evt, metrics, theme, highlightIndex); + } +}; + +Timeline.CompactEventPainter.prototype.paintInstantEvent = function(evt, metrics, theme, highlightIndex) { + if (evt.isImprecise()) { + this.paintImpreciseInstantEvent(evt, metrics, theme, highlightIndex); + } else { + this.paintPreciseInstantEvent(evt, metrics, theme, highlightIndex); + } +} + +Timeline.CompactEventPainter.prototype.paintDurationEvent = function(evt, metrics, theme, highlightIndex) { + if (evt.isImprecise()) { + this.paintImpreciseDurationEvent(evt, metrics, theme, highlightIndex); + } else { + this.paintPreciseDurationEvent(evt, metrics, theme, highlightIndex); + } +} + +Timeline.CompactEventPainter.prototype.paintPreciseInstantEvent = function(evt, metrics, theme, highlightIndex) { + var commonData = { + tooltip: evt.getProperty("tooltip") || evt.getText() + }; + + var iconData = { + url: evt.getIcon() + }; + if (iconData.url == null) { + iconData.url = metrics.defaultIcon; + iconData.width = metrics.defaultIconWidth; + iconData.height = metrics.defaultIconHeight; + iconData.className = "timeline-event-icon-default"; + } else { + iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth; + iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight; + } + + var labelData = { + text: evt.getText(), + color: evt.getTextColor() || evt.getColor(), + className: evt.getClassName() + }; + + var result = this.paintTapeIconLabel( + evt.getStart(), + commonData, + null, // no tape data + iconData, + labelData, + metrics, + theme, + highlightIndex + ); + + var self = this; + var clickHandler = function(elmt, domEvt, target) { + return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt); + }; + SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler); + SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler); + + this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt; +}; + +Timeline.CompactEventPainter.prototype.paintCompositePreciseInstantEvents = function(events, metrics, theme, highlightIndex) { + var evt = events[0]; + + var tooltips = []; + for (var i = 0; i < events.length; i++) { + tooltips.push(events[i].getProperty("tooltip") || events[i].getText()); + } + var commonData = { + tooltip: tooltips.join("; ") + }; + + var iconData = { + url: metrics.compositeIcon, + width: metrics.compositeIconWidth, + height: metrics.compositeIconHeight, + className: "timeline-event-icon-composite" + }; + + var labelData = { + text: String.substitute(this._params.compositeEventLabelTemplate, [ events.length ]) + }; + + var result = this.paintTapeIconLabel( + evt.getStart(), + commonData, + null, // no tape data + iconData, + labelData, + metrics, + theme, + highlightIndex + ); + + var self = this; + var clickHandler = function(elmt, domEvt, target) { + return self._onClickMultiplePreciseInstantEvent(result.iconElmtData.elmt, domEvt, events); + }; + + SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler); + SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler); + + for (var i = 0; i < events.length; i++) { + this._eventIdToElmt[events[i].getID()] = result.iconElmtData.elmt; + } +}; + +Timeline.CompactEventPainter.prototype.paintStackedPreciseInstantEvents = function(events, metrics, theme, highlightIndex) { + var limit = "limit" in this._params.stackConcurrentPreciseInstantEvents ? + this._params.stackConcurrentPreciseInstantEvents.limit : 10; + var moreMessageTemplate = "moreMessageTemplate" in this._params.stackConcurrentPreciseInstantEvents ? + this._params.stackConcurrentPreciseInstantEvents.moreMessageTemplate : "%0 More Events"; + var showMoreMessage = limit <= events.length - 2; // We want at least 2 more events above the limit. + // Otherwise we'd need the singular case of "1 More Event" + + var band = this._band; + var getPixelOffset = function(date) { + return Math.round(band.dateToPixelOffset(date)); + }; + var getIconData = function(evt) { + var iconData = { + url: evt.getIcon() + }; + if (iconData.url == null) { + iconData.url = metrics.defaultStackIcon; + iconData.width = metrics.defaultStackIconWidth; + iconData.height = metrics.defaultStackIconHeight; + iconData.className = "timeline-event-icon-stack timeline-event-icon-default"; + } else { + iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth; + iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight; + iconData.className = "timeline-event-icon-stack"; + } + return iconData; + }; + + var firstIconData = getIconData(events[0]); + var horizontalIncrement = 5; + var leftIconEdge = 0; + var totalLabelWidth = 0; + var totalLabelHeight = 0; + var totalIconHeight = 0; + + var records = []; + for (var i = 0; i < events.length && (!showMoreMessage || i < limit); i++) { + var evt = events[i]; + var text = evt.getText(); + var iconData = getIconData(evt); + var labelSize = this._frc.computeSize(text); + var record = { + text: text, + iconData: iconData, + labelSize: labelSize, + iconLeft: firstIconData.width + i * horizontalIncrement - iconData.width + }; + record.labelLeft = firstIconData.width + i * horizontalIncrement + metrics.iconLabelGap; + record.top = totalLabelHeight; + records.push(record); + + leftIconEdge = Math.min(leftIconEdge, record.iconLeft); + totalLabelHeight += labelSize.height; + totalLabelWidth = Math.max(totalLabelWidth, record.labelLeft + labelSize.width); + totalIconHeight = Math.max(totalIconHeight, record.top + iconData.height); + } + if (showMoreMessage) { + var moreMessage = String.substitute(moreMessageTemplate, [ events.length - limit ]); + + var moreMessageLabelSize = this._frc.computeSize(moreMessage); + var moreMessageLabelLeft = firstIconData.width + (limit - 1) * horizontalIncrement + metrics.iconLabelGap; + var moreMessageLabelTop = totalLabelHeight; + + totalLabelHeight += moreMessageLabelSize.height; + totalLabelWidth = Math.max(totalLabelWidth, moreMessageLabelLeft + moreMessageLabelSize.width); + } + totalLabelWidth += metrics.labelRightMargin; + totalLabelHeight += metrics.labelBottomMargin; + totalIconHeight += metrics.iconBottomMargin; + + var anchorPixel = getPixelOffset(events[0].getStart()); + var newTracks = []; + + var trackCount = Math.ceil(Math.max(totalIconHeight, totalLabelHeight) / metrics.trackHeight); + var rightIconEdge = firstIconData.width + (events.length - 1) * horizontalIncrement; + for (var i = 0; i < trackCount; i++) { + newTracks.push({ start: leftIconEdge, end: rightIconEdge }); + } + var labelTrackCount = Math.ceil(totalLabelHeight / metrics.trackHeight); + for (var i = 0; i < labelTrackCount; i++) { + var track = newTracks[i]; + track.end = Math.max(track.end, totalLabelWidth); + } + + var firstTrack = this._fitTracks(anchorPixel, newTracks); + var verticalPixelOffset = firstTrack * metrics.trackHeight + metrics.trackOffset; + + var iconStackDiv = this._timeline.getDocument().createElement("div"); + iconStackDiv.className = 'timeline-event-icon-stack'; + iconStackDiv.style.position = "absolute"; + iconStackDiv.style.overflow = "visible"; + iconStackDiv.style.left = anchorPixel + "px"; + iconStackDiv.style.top = verticalPixelOffset + "px"; + iconStackDiv.style.width = rightIconEdge + "px"; + iconStackDiv.style.height = totalIconHeight + "px"; + iconStackDiv.innerHTML = "<div style='position: relative'></div>"; + this._eventLayer.appendChild(iconStackDiv); + + var self = this; + var onMouseOver = function(domEvt) { + try { + var n = parseInt(this.getAttribute("index")); + var childNodes = iconStackDiv.firstChild.childNodes; + for (var i = 0; i < childNodes.length; i++) { + var child = childNodes[i]; + if (i == n) { + child.style.zIndex = childNodes.length; + } else { + child.style.zIndex = childNodes.length - i; + } + } + } catch (e) { + } + }; + var paintEvent = function(index) { + var record = records[index]; + var evt = events[index]; + var tooltip = evt.getProperty("tooltip") || evt.getText(); + + var labelElmtData = self._paintEventLabel( + { tooltip: tooltip }, + { text: record.text }, + anchorPixel + record.labelLeft, + verticalPixelOffset + record.top, + record.labelSize.width, + record.labelSize.height, + theme + ); + labelElmtData.elmt.setAttribute("index", index); + labelElmtData.elmt.onmouseover = onMouseOver; + + var img = SimileAjax.Graphics.createTranslucentImage(record.iconData.url); + var iconDiv = self._timeline.getDocument().createElement("div"); + iconDiv.className = 'timeline-event-icon' + ("className" in record.iconData ? (" " + record.iconData.className) : ""); + iconDiv.style.left = record.iconLeft + "px"; + iconDiv.style.top = record.top + "px"; + iconDiv.style.zIndex = (records.length - index); + iconDiv.appendChild(img); + iconDiv.setAttribute("index", index); + iconDiv.onmouseover = onMouseOver; + + iconStackDiv.firstChild.appendChild(iconDiv); + + var clickHandler = function(elmt, domEvt, target) { + return self._onClickInstantEvent(labelElmtData.elmt, domEvt, evt); + }; + + SimileAjax.DOM.registerEvent(iconDiv, "mousedown", clickHandler); + SimileAjax.DOM.registerEvent(labelElmtData.elmt, "mousedown", clickHandler); + + self._eventIdToElmt[evt.getID()] = iconDiv; + }; + for (var i = 0; i < records.length; i++) { + paintEvent(i); + } + + if (showMoreMessage) { + var moreEvents = events.slice(limit); + var moreMessageLabelElmtData = this._paintEventLabel( + { tooltip: moreMessage }, + { text: moreMessage }, + anchorPixel + moreMessageLabelLeft, + verticalPixelOffset + moreMessageLabelTop, + moreMessageLabelSize.width, + moreMessageLabelSize.height, + theme + ); + + var moreMessageClickHandler = function(elmt, domEvt, target) { + return self._onClickMultiplePreciseInstantEvent(moreMessageLabelElmtData.elmt, domEvt, moreEvents); + }; + SimileAjax.DOM.registerEvent(moreMessageLabelElmtData.elmt, "mousedown", moreMessageClickHandler); + + for (var i = 0; i < moreEvents.length; i++) { + this._eventIdToElmt[moreEvents[i].getID()] = moreMessageLabelElmtData.elmt; + } + } + //this._createHighlightDiv(highlightIndex, iconElmtData, theme); +}; + +Timeline.CompactEventPainter.prototype.paintImpreciseInstantEvent = function(evt, metrics, theme, highlightIndex) { + var commonData = { + tooltip: evt.getProperty("tooltip") || evt.getText() + }; + + var tapeData = { + start: evt.getStart(), + end: evt.getEnd(), + latestStart: evt.getLatestStart(), + earliestEnd: evt.getEarliestEnd(), + isInstant: true + }; + + var iconData = { + url: evt.getIcon() + }; + if (iconData.url == null) { + iconData = null; + } else { + iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth; + iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight; + } + + var labelData = { + text: evt.getText(), + color: evt.getTextColor() || evt.getColor(), + className: evt.getClassName() + }; + + var result = this.paintTapeIconLabel( + evt.getStart(), + commonData, + tapeData, // no tape data + iconData, + labelData, + metrics, + theme, + highlightIndex + ); + + var self = this; + var clickHandler = iconData != null ? + function(elmt, domEvt, target) { + return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt); + } : + function(elmt, domEvt, target) { + return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt); + }; + + SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler); + SimileAjax.DOM.registerEvent(result.impreciseTapeElmtData.elmt, "mousedown", clickHandler); + + if (iconData != null) { + SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler); + this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt; + } else { + this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt; + } +}; + +Timeline.CompactEventPainter.prototype.paintPreciseDurationEvent = function(evt, metrics, theme, highlightIndex) { + var commonData = { + tooltip: evt.getProperty("tooltip") || evt.getText() + }; + + var tapeData = { + start: evt.getStart(), + end: evt.getEnd(), + isInstant: false + }; + + var iconData = { + url: evt.getIcon() + }; + if (iconData.url == null) { + iconData = null; + } else { + iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth; + iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight; + } + + var labelData = { + text: evt.getText(), + color: evt.getTextColor() || evt.getColor(), + className: evt.getClassName() + }; + + var result = this.paintTapeIconLabel( + evt.getLatestStart(), + commonData, + tapeData, // no tape data + iconData, + labelData, + metrics, + theme, + highlightIndex + ); + + var self = this; + var clickHandler = iconData != null ? + function(elmt, domEvt, target) { + return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt); + } : + function(elmt, domEvt, target) { + return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt); + }; + + SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler); + SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt, "mousedown", clickHandler); + + if (iconData != null) { + SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler); + this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt; + } else { + this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt; + } +}; + +Timeline.CompactEventPainter.prototype.paintImpreciseDurationEvent = function(evt, metrics, theme, highlightIndex) { + var commonData = { + tooltip: evt.getProperty("tooltip") || evt.getText() + }; + + var tapeData = { + start: evt.getStart(), + end: evt.getEnd(), + latestStart: evt.getLatestStart(), + earliestEnd: evt.getEarliestEnd(), + isInstant: false + }; + + var iconData = { + url: evt.getIcon() + }; + if (iconData.url == null) { + iconData = null; + } else { + iconData.width = evt.getProperty("iconWidth") || metrics.customIconWidth; + iconData.height = evt.getProperty("iconHeight") || metrics.customIconHeight; + } + + var labelData = { + text: evt.getText(), + color: evt.getTextColor() || evt.getColor(), + className: evt.getClassName() + }; + + var result = this.paintTapeIconLabel( + evt.getLatestStart(), + commonData, + tapeData, // no tape data + iconData, + labelData, + metrics, + theme, + highlightIndex + ); + + var self = this; + var clickHandler = iconData != null ? + function(elmt, domEvt, target) { + return self._onClickInstantEvent(result.iconElmtData.elmt, domEvt, evt); + } : + function(elmt, domEvt, target) { + return self._onClickInstantEvent(result.labelElmtData.elmt, domEvt, evt); + }; + + SimileAjax.DOM.registerEvent(result.labelElmtData.elmt, "mousedown", clickHandler); + SimileAjax.DOM.registerEvent(result.tapeElmtData.elmt, "mousedown", clickHandler); + + if (iconData != null) { + SimileAjax.DOM.registerEvent(result.iconElmtData.elmt, "mousedown", clickHandler); + this._eventIdToElmt[evt.getID()] = result.iconElmtData.elmt; + } else { + this._eventIdToElmt[evt.getID()] = result.labelElmtData.elmt; + } +}; + +Timeline.CompactEventPainter.prototype.paintTapeIconLabel = function( + anchorDate, + commonData, + tapeData, + iconData, + labelData, + metrics, + theme, + highlightIndex +) { + var band = this._band; + var getPixelOffset = function(date) { + return Math.round(band.dateToPixelOffset(date)); + }; + + var anchorPixel = getPixelOffset(anchorDate); + var newTracks = []; + + var tapeHeightOccupied = 0; // how many pixels (vertically) the tape occupies, including bottom margin + var tapeTrackCount = 0; // how many tracks the tape takes up, usually just 1 + var tapeLastTrackExtraSpace = 0; // on the last track that the tape occupies, how many pixels are left (for icon and label to occupy as well) + if (tapeData != null) { + tapeHeightOccupied = metrics.tapeHeight + metrics.tapeBottomMargin; + tapeTrackCount = Math.ceil(metrics.tapeHeight / metrics.trackHeight); + + var tapeEndPixelOffset = getPixelOffset(tapeData.end) - anchorPixel; + var tapeStartPixelOffset = getPixelOffset(tapeData.start) - anchorPixel; + + for (var t = 0; t < tapeTrackCount; t++) { + newTracks.push({ start: tapeStartPixelOffset, end: tapeEndPixelOffset }); + } + + tapeLastTrackExtraSpace = metrics.trackHeight - (tapeHeightOccupied % metrics.tapeHeight); + } + + var iconStartPixelOffset = 0; // where the icon starts compared to the anchor pixel; + // this can be negative if the icon is center-aligned around the anchor + var iconHorizontalSpaceOccupied = 0; // how many pixels the icon take up from the anchor pixel, + // including the gap between the icon and the label + if (iconData != null) { + if ("iconAlign" in iconData && iconData.iconAlign == "center") { + iconStartPixelOffset = -Math.floor(iconData.width / 2); + } + iconHorizontalSpaceOccupied = iconStartPixelOffset + iconData.width + metrics.iconLabelGap; + + if (tapeTrackCount > 0) { + newTracks[tapeTrackCount - 1].end = Math.max(newTracks[tapeTrackCount - 1].end, iconHorizontalSpaceOccupied); + } + + var iconHeight = iconData.height + metrics.iconBottomMargin + tapeLastTrackExtraSpace; + while (iconHeight > 0) { + newTracks.push({ start: iconStartPixelOffset, end: iconHorizontalSpaceOccupied }); + iconHeight -= metrics.trackHeight; + } + } + + var text = labelData.text; + var labelSize = this._frc.computeSize(text); + var labelHeight = labelSize.height + metrics.labelBottomMargin + tapeLastTrackExtraSpace; + var labelEndPixelOffset = iconHorizontalSpaceOccupied + labelSize.width + metrics.labelRightMargin; + if (tapeTrackCount > 0) { + newTracks[tapeTrackCount - 1].end = Math.max(newTracks[tapeTrackCount - 1].end, labelEndPixelOffset); + } + for (var i = 0; labelHeight > 0; i++) { + if (tapeTrackCount + i < newTracks.length) { + var track = newTracks[tapeTrackCount + i]; + track.end = labelEndPixelOffset; + } else { + newTracks.push({ start: 0, end: labelEndPixelOffset }); + } + labelHeight -= metrics.trackHeight; + } + + /* + * Try to fit the new track on top of the existing tracks, then + * render the various elements. + */ + var firstTrack = this._fitTracks(anchorPixel, newTracks); + var verticalPixelOffset = firstTrack * metrics.trackHeight + metrics.trackOffset; + var result = {}; + + result.labelElmtData = this._paintEventLabel( + commonData, + labelData, + anchorPixel + iconHorizontalSpaceOccupied, + verticalPixelOffset + tapeHeightOccupied, + labelSize.width, + labelSize.height, + theme + ); + + if (tapeData != null) { + if ("latestStart" in tapeData || "earliestEnd" in tapeData) { + result.impreciseTapeElmtData = this._paintEventTape( + commonData, + tapeData, + metrics.tapeHeight, + verticalPixelOffset, + getPixelOffset(tapeData.start), + getPixelOffset(tapeData.end), + theme.event.duration.impreciseColor, + theme.event.duration.impreciseOpacity, + metrics, + theme + ); + } + if (!tapeData.isInstant && "start" in tapeData && "end" in tapeData) { + result.tapeElmtData = this._paintEventTape( + commonData, + tapeData, + metrics.tapeHeight, + verticalPixelOffset, + anchorPixel, + getPixelOffset("earliestEnd" in tapeData ? tapeData.earliestEnd : tapeData.end), + tapeData.color, + 100, + metrics, + theme + ); + } + } + + if (iconData != null) { + result.iconElmtData = this._paintEventIcon( + commonData, + iconData, + verticalPixelOffset + tapeHeightOccupied, + anchorPixel + iconStartPixelOffset, + metrics, + theme + ); + } + //this._createHighlightDiv(highlightIndex, iconElmtData, theme); + + return result; +}; + +Timeline.CompactEventPainter.prototype._fitTracks = function(anchorPixel, newTracks) { + var firstTrack; + for (firstTrack = 0; firstTrack < this._tracks.length; firstTrack++) { + var fit = true; + for (var j = 0; j < newTracks.length && (firstTrack + j) < this._tracks.length; j++) { + var existingTrack = this._tracks[firstTrack + j]; + var newTrack = newTracks[j]; + if (anchorPixel + newTrack.start < existingTrack) { + fit = false; + break; + } + } + + if (fit) { + break; + } + } + for (var i = 0; i < newTracks.length; i++) { + this._tracks[firstTrack + i] = anchorPixel + newTracks[i].end; + } + + return firstTrack; +}; + + +Timeline.CompactEventPainter.prototype._paintEventIcon = function(commonData, iconData, top, left, metrics, theme) { + var img = SimileAjax.Graphics.createTranslucentImage(iconData.url); + var iconDiv = this._timeline.getDocument().createElement("div"); + iconDiv.className = 'timeline-event-icon' + ("className" in iconData ? (" " + iconData.className) : ""); + iconDiv.style.left = left + "px"; + iconDiv.style.top = top + "px"; + iconDiv.appendChild(img); + + if ("tooltip" in commonData && typeof commonData.tooltip == "string") { + iconDiv.title = commonData.tooltip; + } + + this._eventLayer.appendChild(iconDiv); + + return { + left: left, + top: top, + width: metrics.iconWidth, + height: metrics.iconHeight, + elmt: iconDiv + }; +}; + +Timeline.CompactEventPainter.prototype._paintEventLabel = function(commonData, labelData, left, top, width, height, theme) { + var doc = this._timeline.getDocument(); + + var labelDiv = doc.createElement("div"); + labelDiv.className = 'timeline-event-label'; + + labelDiv.style.left = left + "px"; + labelDiv.style.width = (width + 1) + "px"; + labelDiv.style.top = top + "px"; + labelDiv.innerHTML = labelData.text; + + if ("tooltip" in commonData && typeof commonData.tooltip == "string") { + labelDiv.title = commonData.tooltip; + } + if ("color" in labelData && typeof labelData.color == "string") { + labelDiv.style.color = labelData.color; + } + if ("className" in labelData && typeof labelData.className == "string") { + labelDiv.className += ' ' + labelData.className; + } + + this._eventLayer.appendChild(labelDiv); + + return { + left: left, + top: top, + width: width, + height: height, + elmt: labelDiv + }; +}; + +Timeline.CompactEventPainter.prototype._paintEventTape = function( + commonData, tapeData, height, top, startPixel, endPixel, color, opacity, metrics, theme) { + + var width = endPixel - startPixel; + + var tapeDiv = this._timeline.getDocument().createElement("div"); + tapeDiv.className = "timeline-event-tape" + + tapeDiv.style.left = startPixel + "px"; + tapeDiv.style.top = top + "px"; + tapeDiv.style.width = width + "px"; + tapeDiv.style.height = height + "px"; + + if ("tooltip" in commonData && typeof commonData.tooltip == "string") { + tapeDiv.title = commonData.tooltip; + } + if (color != null && typeof tapeData.color == "string") { + tapeDiv.style.backgroundColor = color; + } + + if ("backgroundImage" in tapeData && typeof tapeData.backgroundImage == "string") { + tapeDiv.style.backgroundImage = "url(" + backgroundImage + ")"; + tapeDiv.style.backgroundRepeat = + ("backgroundRepeat" in tapeData && typeof tapeData.backgroundRepeat == "string") + ? tapeData.backgroundRepeat : 'repeat'; + } + + SimileAjax.Graphics.setOpacity(tapeDiv, opacity); + + if ("className" in tapeData && typeof tapeData.className == "string") { + tapeDiv.className += ' ' + tapeData.className; + } + + this._eventLayer.appendChild(tapeDiv); + + return { + left: startPixel, + top: top, + width: width, + height: height, + elmt: tapeDiv + }; +} + +Timeline.CompactEventPainter.prototype._createHighlightDiv = function(highlightIndex, dimensions, theme) { + if (highlightIndex >= 0) { + var doc = this._timeline.getDocument(); + var eventTheme = theme.event; + + var color = eventTheme.highlightColors[Math.min(highlightIndex, eventTheme.highlightColors.length - 1)]; + + var div = doc.createElement("div"); + div.style.position = "absolute"; + div.style.overflow = "hidden"; + div.style.left = (dimensions.left - 2) + "px"; + div.style.width = (dimensions.width + 4) + "px"; + div.style.top = (dimensions.top - 2) + "px"; + div.style.height = (dimensions.height + 4) + "px"; +// div.style.background = color; + + this._highlightLayer.appendChild(div); + } +}; + +Timeline.CompactEventPainter.prototype._onClickMultiplePreciseInstantEvent = function(icon, domEvt, events) { + var c = SimileAjax.DOM.getPageCoordinates(icon); + this._showBubble( + c.left + Math.ceil(icon.offsetWidth / 2), + c.top + Math.ceil(icon.offsetHeight / 2), + events + ); + + var ids = []; + for (var i = 0; i < events.length; i++) { + ids.push(events[i].getID()); + } + this._fireOnSelect(ids); + + domEvt.cancelBubble = true; + SimileAjax.DOM.cancelEvent(domEvt); + + return false; +}; + +Timeline.CompactEventPainter.prototype._onClickInstantEvent = function(icon, domEvt, evt) { + var c = SimileAjax.DOM.getPageCoordinates(icon); + this._showBubble( + c.left + Math.ceil(icon.offsetWidth / 2), + c.top + Math.ceil(icon.offsetHeight / 2), + [evt] + ); + this._fireOnSelect([evt.getID()]); + + domEvt.cancelBubble = true; + SimileAjax.DOM.cancelEvent(domEvt); + return false; +}; + +Timeline.CompactEventPainter.prototype._onClickDurationEvent = function(target, domEvt, evt) { + if ("pageX" in domEvt) { + var x = domEvt.pageX; + var y = domEvt.pageY; + } else { + var c = SimileAjax.DOM.getPageCoordinates(target); + var x = domEvt.offsetX + c.left; + var y = domEvt.offsetY + c.top; + } + this._showBubble(x, y, [evt]); + this._fireOnSelect([evt.getID()]); + + domEvt.cancelBubble = true; + SimileAjax.DOM.cancelEvent(domEvt); + return false; +}; + +Timeline.CompactEventPainter.prototype.showBubble = function(evt) { + var elmt = this._eventIdToElmt[evt.getID()]; + if (elmt) { + var c = SimileAjax.DOM.getPageCoordinates(elmt); + this._showBubble(c.left + elmt.offsetWidth / 2, c.top + elmt.offsetHeight / 2, [evt]); + } +}; + +Timeline.CompactEventPainter.prototype._showBubble = function(x, y, evts) { + var div = document.createElement("div"); + + evts = ("fillInfoBubble" in evts) ? [evts] : evts; + for (var i = 0; i < evts.length; i++) { + var div2 = document.createElement("div"); + div.appendChild(div2); + + evts[i].fillInfoBubble(div2, this._params.theme, this._band.getLabeller()); + } + + SimileAjax.WindowManager.cancelPopups(); + SimileAjax.Graphics.createBubbleForContentAndPoint(div, x, y, this._params.theme.event.bubble.width); +}; + +Timeline.CompactEventPainter.prototype._fireOnSelect = function(eventIDs) { + for (var i = 0; i < this._onSelectListeners.length; i++) { + this._onSelectListeners[i](eventIDs); + } +}; Added: openoffice/ooo-site/trunk/content/scripts/simile-widget/timeline/2.3.1/scripts/decorators.js URL: http://svn.apache.org/viewvc/openoffice/ooo-site/trunk/content/scripts/simile-widget/timeline/2.3.1/scripts/decorators.js?rev=1791126&view=auto ============================================================================== --- openoffice/ooo-site/trunk/content/scripts/simile-widget/timeline/2.3.1/scripts/decorators.js (added) +++ openoffice/ooo-site/trunk/content/scripts/simile-widget/timeline/2.3.1/scripts/decorators.js Wed Apr 12 14:36:37 2017 @@ -0,0 +1,184 @@ +/*================================================== + * Span Highlight Decorator + *================================================== + */ + +Timeline.SpanHighlightDecorator = function(params) { + // When evaluating params, test against null. Not "p in params". Testing against + // null enables caller to explicitly request the default. Testing against "in" means + // that the param has to be ommitted to get the default. + this._unit = params.unit != null ? params.unit : SimileAjax.NativeDateUnit; + this._startDate = (typeof params.startDate == "string") ? + this._unit.parseFromObject(params.startDate) : params.startDate; + this._endDate = (typeof params.endDate == "string") ? + this._unit.parseFromObject(params.endDate) : params.endDate; + this._startLabel = params.startLabel != null ? params.startLabel : ""; // not null! + this._endLabel = params.endLabel != null ? params.endLabel : ""; // not null! + this._color = params.color; + this._cssClass = params.cssClass != null ? params.cssClass : null; + this._opacity = params.opacity != null ? params.opacity : 100; + // Default z is 10, behind everything but background grid. + // If inFront, then place just behind events, in front of everything else + this._zIndex = (params.inFront != null && params.inFront) ? 113 : 10; +}; + +Timeline.SpanHighlightDecorator.prototype.initialize = function(band, timeline) { + this._band = band; + this._timeline = timeline; + + this._layerDiv = null; +}; + +Timeline.SpanHighlightDecorator.prototype.paint = function() { + if (this._layerDiv != null) { + this._band.removeLayerDiv(this._layerDiv); + } + this._layerDiv = this._band.createLayerDiv(this._zIndex); + this._layerDiv.setAttribute("name", "span-highlight-decorator"); // for debugging + this._layerDiv.style.display = "none"; + + var minDate = this._band.getMinDate(); + var maxDate = this._band.getMaxDate(); + + if (this._unit.compare(this._startDate, maxDate) < 0 && + this._unit.compare(this._endDate, minDate) > 0) { + + minDate = this._unit.later(minDate, this._startDate); + maxDate = this._unit.earlier(maxDate, this._endDate); + + var minPixel = this._band.dateToPixelOffset(minDate); + var maxPixel = this._band.dateToPixelOffset(maxDate); + + var doc = this._timeline.getDocument(); + + var createTable = function() { + var table = doc.createElement("table"); + table.insertRow(0).insertCell(0); + return table; + }; + + var div = doc.createElement("div"); + div.className='timeline-highlight-decorator' + if(this._cssClass) { + div.className += ' ' + this._cssClass; + } + if(this._color != null) { + div.style.backgroundColor = this._color; + } + if (this._opacity < 100) { + SimileAjax.Graphics.setOpacity(div, this._opacity); + } + this._layerDiv.appendChild(div); + + var tableStartLabel = createTable(); + tableStartLabel.className = 'timeline-highlight-label timeline-highlight-label-start' + var tdStart = tableStartLabel.rows[0].cells[0] + tdStart.innerHTML = this._startLabel; + if (this._cssClass) { + tdStart.className = 'label_' + this._cssClass; + } + this._layerDiv.appendChild(tableStartLabel); + + var tableEndLabel = createTable(); + tableEndLabel.className = 'timeline-highlight-label timeline-highlight-label-end' + var tdEnd = tableEndLabel.rows[0].cells[0] + tdEnd.innerHTML = this._endLabel; + if (this._cssClass) { + tdEnd.className = 'label_' + this._cssClass; + } + this._layerDiv.appendChild(tableEndLabel); + + if (this._timeline.isHorizontal()){ + div.style.left = minPixel + "px"; + div.style.width = (maxPixel - minPixel) + "px"; + + tableStartLabel.style.right = (this._band.getTotalViewLength() - minPixel) + "px"; + tableStartLabel.style.width = (this._startLabel.length) + "em"; + + tableEndLabel.style.left = maxPixel + "px"; + tableEndLabel.style.width = (this._endLabel.length) + "em"; + + } else { + div.style.top = minPixel + "px"; + div.style.height = (maxPixel - minPixel) + "px"; + + tableStartLabel.style.bottom = minPixel + "px"; + tableStartLabel.style.height = "1.5px"; + + tableEndLabel.style.top = maxPixel + "px"; + tableEndLabel.style.height = "1.5px"; + } + } + this._layerDiv.style.display = "block"; +}; + +Timeline.SpanHighlightDecorator.prototype.softPaint = function() { +}; + +/*================================================== + * Point Highlight Decorator + *================================================== + */ + +Timeline.PointHighlightDecorator = function(params) { + this._unit = params.unit != null ? params.unit : SimileAjax.NativeDateUnit; + this._date = (typeof params.date == "string") ? + this._unit.parseFromObject(params.date) : params.date; + this._width = params.width != null ? params.width : 10; + // Since the width is used to calculate placements (see minPixel, below), we + // specify width here, not in css. + this._color = params.color; + this._cssClass = params.cssClass != null ? params.cssClass : ''; + this._opacity = params.opacity != null ? params.opacity : 100; +}; + +Timeline.PointHighlightDecorator.prototype.initialize = function(band, timeline) { + this._band = band; + this._timeline = timeline; + this._layerDiv = null; +}; + +Timeline.PointHighlightDecorator.prototype.paint = function() { + if (this._layerDiv != null) { + this._band.removeLayerDiv(this._layerDiv); + } + this._layerDiv = this._band.createLayerDiv(10); + this._layerDiv.setAttribute("name", "span-highlight-decorator"); // for debugging + this._layerDiv.style.display = "none"; + + var minDate = this._band.getMinDate(); + var maxDate = this._band.getMaxDate(); + + if (this._unit.compare(this._date, maxDate) < 0 && + this._unit.compare(this._date, minDate) > 0) { + + var pixel = this._band.dateToPixelOffset(this._date); + var minPixel = pixel - Math.round(this._width / 2); + + var doc = this._timeline.getDocument(); + + var div = doc.createElement("div"); + div.className='timeline-highlight-point-decorator'; + div.className += ' ' + this._cssClass; + + if(this._color != null) { + div.style.backgroundColor = this._color; + } + if (this._opacity < 100) { + SimileAjax.Graphics.setOpacity(div, this._opacity); + } + this._layerDiv.appendChild(div); + + if (this._timeline.isHorizontal()) { + div.style.left = minPixel + "px"; + div.style.width = this._width; + } else { + div.style.top = minPixel + "px"; + div.style.height = this._width; + } + } + this._layerDiv.style.display = "block"; +}; + +Timeline.PointHighlightDecorator.prototype.softPaint = function() { +};
