'use strict'; /** * Licensed Materials - Property of IBM * IBM Cognos Products: Storytelling * (C) Copyright IBM Corp. 2014, 2018 * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ define(['baglass/core-client/js/core-client/ui/core/View', 'text!./templates/TimelineRulerView.html', 'jquery'], function (View, Template, $) { var MINOR_TICK_COLOUR = '#cccccc'; var MAJOR_TICK_COLOUR = '#c0c0c0'; var DEFAULT_FILL_COLOUR = '#888888'; var HIGH_CONTRAST_COLOUR = '#AFAFAF'; var TimelineRulerView = View.extend({ templateString: Template, lastOffset: 0, init: function init(options) { TimelineRulerView.inherited('init', this, arguments); // Use a different colour that passes contrast ratio standard when in high contrast mode if ($('body').hasClass('highcontrast')) { this.majorTickColour = HIGH_CONTRAST_COLOUR; this.minorTickColour = HIGH_CONTRAST_COLOUR; this.fillColour = HIGH_CONTRAST_COLOUR; } else { this.majorTickColour = MAJOR_TICK_COLOUR; this.minorTickColour = MINOR_TICK_COLOUR; this.fillColour = DEFAULT_FILL_COLOUR; } this.controller = options.controller; this.scaleManager = options.scaleManager; this._useDiv = options.useDiv === true; }, remove: function remove() { $(window).off('resize.privateViewEvents' + this.viewId); if (this.$ruler) { this.$ruler.off('click'); this.$ruler = null; } TimelineRulerView.inherited('remove', this, arguments); }, /** * Renders the timeline. * * @returns */ render: function render() { var sHtml = this.dotTemplate({ canvas: !this._useDiv }); this.$el.html(sHtml); // this.$ruler will be a canvas element if _useDiv is false otherwise it is a div element this.$ruler = this.$el.find('.ruler'); this.$ruler.on('click', this.onRulerClick.bind(this)); $(window).off('resize.privateViewEvents' + this.viewId).on('resize.privateViewEvents' + this.viewId, this.onResize.bind(this)); this._updateCanvasWidth(); }, _updateCanvasWidth: function _updateCanvasWidth() { var width = this.$el.outerWidth(false); var height = this.$el.outerHeight(false); if (!this._useDiv) { this.$ruler[0].width = width; this.$ruler[0].height = height; this.context = this.$ruler[0].getContext('2d'); this.context.fillStyle = this.fillColour; this.context.font = '100 14px HelvNeueforIBM,“Helvetica Neue”,Helvetica,Arial,sans-serif'; } else { this.$ruler.css('width', '100%'); this.$ruler.css('height', height); } }, drawTicks: function drawTicks() { if (!this._useDiv) { // Clear the canvas. this.context.clearRect(0, 0, this.$ruler[0].width, this.$ruler[0].height); var tickWidth = this.scaleInfo.tickWidth; var startCount = 0; var offsetX = 0; if (this.lastOffset > 0) { var ratio = this.lastOffset / tickWidth; startCount = Math.floor(ratio); offsetX = (startCount - ratio) * tickWidth; } var options = { offsetCount: startCount, offsetX: offsetX, depth: this.scaleInfo.depth }; this._drawTicksRecursively(options, this.scaleInfo); } }, setOffsetLeft: function setOffsetLeft(offset) { if (offset !== this.lastOffset) { this.lastOffset = offset; this.refresh(); } }, refresh: function refresh() { this.scaleInfo = this._calculateScaleInfo(); this._updateCanvasWidth(); this.drawTicks(); }, /* * View events. */ onResize: function onResize() { if (this.scaleInfo && this.$el.is(':visible')) { // We only resize if the view is visible. this._updateCanvasWidth(); this.drawTicks(); } }, onRulerClick: function onRulerClick(event) { var time = this._getTimeForPosition(event.pageX); var playing = this.controller.isPlaying(); if (playing) { this.controller.pause(); } this.controller.setCurrentTime(time); if (playing) { this.controller.play(); } }, /* * Helpers */ _drawTicksRecursively: function _drawTicksRecursively(options, info, currentDepth) { var context = this.context; currentDepth = currentDepth || 0; if (currentDepth === 0) { this._drawMajorTicks(options, info); } else { this._drawMinorTicks(options, info, currentDepth); } if (info.minorTicks) { // Start recursively drawing minor ticks. this._drawTicksRecursively(options, info.minorTicks, currentDepth + 1); } else if (currentDepth >= options.depth - 1) { // Base case in the recursive function. Draw the path for all the depths >= 1 (minor ticks). context.stroke(); } }, _drawMajorTicks: function _drawMajorTicks(options, info) { var count = options.offsetCount; var width = this.$ruler[0].width; var height = this.$ruler[0].height; var context = this.context; context.strokeStyle = this.majorTickColour; context.beginPath(); var i, y, timeLabel; var prevTimeLabel = ''; var tickIncrement = info.tickWidth; for (i = options.offsetX; i < width; i += tickIncrement) { timeLabel = this.controller.getTimeLabel(count * info.tickDuration); // To get the major ticks to display more and look better, tickDuration can be adjusted to a smaller number based on scale factors // When tickDuration becomes smaller, the timeLabel can be returned the same with tickIncrements // Check and don't draw major ticks and label twice if (timeLabel && timeLabel !== prevTimeLabel) { prevTimeLabel = timeLabel; y = 15; context.fillText(timeLabel, i + 3, y + 11); if (i > 0) { // Don't draw a line at the start. context.moveTo(i, y); context.lineTo(i, height); } } count++; } context.stroke(); }, _drawMinorTicks: function _drawMinorTicks(options, info, currentDepth) { var width = this.$ruler[0].width; var height = this.$ruler[0].height; var context = this.context; if (currentDepth === 1) { // Minor ticks are at depth >= 1, set different styles. context.strokeStyle = this.minorTickColour; context.beginPath(); } var i, y; var tickIncrement = info.tickWidth * 2; for (i = options.offsetX + tickIncrement; i < width; i += tickIncrement) { if (i > 0) { y = 40; // Don't draw a line at the start. context.moveTo(i, y); context.lineTo(i, height); } } }, _getScaleInfo: function _getScaleInfo(scale) { var tickDuration; var minScale = this.scaleManager.getMinScale(); var maxScale = this.scaleManager.getMaxScale(); var factor = (scale - minScale) / (maxScale - minScale); if (factor >= 1) { tickDuration = 500; } else if (factor >= 0.5) { tickDuration = 1000; } else if (factor >= 0.25) { tickDuration = 2000; } else if (factor >= 0.125) { tickDuration = 2500; } else if (factor >= 0.0625) { tickDuration = 5000; } else if (factor >= 0.02) { tickDuration = 10000; } else if (factor >= 0.01) { tickDuration = 20000; } else if (factor > 0) { tickDuration = 50000; } else { tickDuration = 100000; } var tickWidth = this.scaleManager.convertTimeToPosition(tickDuration); var info = { tickWidth: tickWidth, tickDuration: tickDuration, depth: 1 }; var minorTicks = this._getScaleInfoHelper(info, scale, tickWidth / 2); if (minorTicks) { info.minorTicks = minorTicks; } return info; }, _getScaleInfoHelper: function _getScaleInfoHelper(context, scale, tickWidth) { var info = null; if (tickWidth > 10) { info = { tickWidth: tickWidth }; context.depth++; // Change the factor to determine how many minor ticks drawn within major ticks // The tickWidth check will have to be adjusted as well to accommodate the drawing // E.g. if the factor is changed to 10, then the condition tickWidth > 5 will have to be done // in that case, the minor ticks can be 10 or 20 for 1 sec depends on the resolution of the device var nestedInfo = this._getScaleInfoHelper(context, scale, tickWidth / 5); if (nestedInfo) { info.minorTicks = nestedInfo; } } return info; }, _calculateScaleInfo: function _calculateScaleInfo() { var scale = this.scaleManager.getScale(); return this._getScaleInfo(scale); }, _getTimeForPosition: function _getTimeForPosition(position) { var info = this.scaleInfo, tickWidth = info.tickWidth, tickDuration = info.tickDuration; return (position - this.$el.offset().left + this.lastOffset) / tickWidth * tickDuration; } }); return TimelineRulerView; }); //# sourceMappingURL=TimelineRulerView.js.map