Socket
Socket
Sign inDemoInstall

timeline

Package Overview
Dependencies
0
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.0.1 to 3.0.2

build/src/views/index.d.ts

314

build/bundle.js

@@ -1,313 +0,1 @@

(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["Timeline"] = factory();
else
root["Timeline"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = "./src/index.ts");
/******/ })
/************************************************************************/
/******/ ({
/***/ "./src/animator.ts":
/*!*************************!*\
!*** ./src/animator.ts ***!
\*************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst props_1 = __webpack_require__(/*! ./models/props */ \"./src/models/props.ts\");\nvar Direction;\n(function (Direction) {\n Direction[Direction[\"Backward\"] = -1] = \"Backward\";\n Direction[Direction[\"Stop\"] = 0] = \"Stop\";\n Direction[Direction[\"Forward\"] = 1] = \"Forward\";\n})(Direction || (Direction = {}));\nclass Animator {\n constructor() {\n this.goToDuration = 300;\n this.zoomToDuration = 300;\n this.interval = .00001;\n this.multipliers = [.25, .5, 1, 2, 4, 8, 16];\n this.multiplier = 1;\n this.direction = Direction.Stop;\n this.elapsedTimeTotal = 0;\n this.modelUpdaters = [];\n this.viewUpdaters = [];\n this.animate = (timestamp) => {\n const elapsedTime = this.prevTimestamp == null ? 0 : timestamp - this.prevTimestamp;\n if (elapsedTime > 0 || this.prevTimestamp == null) {\n if (this.centerMarker == null && this.zoomMarker == null) {\n props_1.default.center = props_1.default.center + (this.interval * this.multiplier * this.direction);\n }\n else if (this.centerMarker != null) {\n const timeRemaining = this.goToDuration - this.elapsedTimeTotal;\n const centerDelta = Math.abs(this.centerMarker - props_1.default.center) / (timeRemaining / elapsedTime);\n if (timeRemaining < elapsedTime) {\n props_1.default.center = this.centerMarker;\n this.stop();\n }\n else\n props_1.default.center = props_1.default.center + (centerDelta * this.direction);\n }\n else if (this.zoomMarker != null) {\n const timeRemaining = this.zoomToDuration - this.elapsedTimeTotal;\n const zoomDelta = (this.zoomMarker - props_1.default.eventsBand.zoomLevel) / (timeRemaining / elapsedTime);\n if (timeRemaining < elapsedTime) {\n props_1.default.eventsBand.zoomLevel = this.zoomMarker;\n this.stop();\n }\n else {\n props_1.default.eventsBand.zoomLevel = props_1.default.eventsBand.zoomLevel + zoomDelta;\n }\n props_1.default.minimapBands.forEach(mmb => {\n if (props_1.default.eventsBand.zoomLevel < mmb.config.zoomLevel) {\n mmb.zoomLevel = props_1.default.eventsBand.zoomLevel;\n }\n else if (mmb.zoomLevel !== mmb.config.zoomLevel) {\n mmb.zoomLevel = mmb.config.zoomLevel;\n }\n });\n }\n this.modelUpdaters.forEach(update => update());\n this.viewUpdaters.forEach(update => update());\n }\n this.elapsedTimeTotal += elapsedTime;\n if (this.isPlaying() || this.zoomMarker != null) {\n if ((props_1.default.center > 0 && props_1.default.center < 1) || this.centerMarker != null) {\n this.prevTimestamp = timestamp;\n requestAnimationFrame(this.animate);\n }\n else {\n this.stop();\n }\n }\n };\n }\n registerModelUpdaters(update) {\n this.modelUpdaters.push(update);\n }\n registerViewUpdaters(update) {\n this.viewUpdaters.push(update);\n }\n accelerate() {\n const index = this.multipliers.indexOf(this.multiplier);\n if (index === this.multipliers.length - 1)\n return this.multipliers[this.multipliers.length - 1];\n this.multiplier = this.multipliers[index + 1];\n return this.multiplier;\n }\n decelerate() {\n const index = this.multipliers.indexOf(this.multiplier);\n if (index === 0)\n return this.multipliers[0];\n this.multiplier = this.multipliers[index - 1];\n return this.multiplier;\n }\n goTo(nextCenter) {\n this.centerMarker = nextCenter;\n if (nextCenter > props_1.default.center)\n this.playForward();\n else\n this.playBackward();\n }\n zoomTo(nextZoomLevel) {\n if (nextZoomLevel < 0)\n nextZoomLevel = 0;\n this.zoomMarker = nextZoomLevel;\n this.play();\n }\n speed(multiplier) {\n const multiplier2 = parseFloat(multiplier);\n if (this.multipliers.indexOf(multiplier2) === -1)\n return;\n this.multiplier = multiplier2;\n }\n isPlaying() {\n return this.direction !== Direction.Stop;\n }\n isPlayingForward() {\n return this.direction === Direction.Forward;\n }\n isPlayingBackward() {\n return this.direction === Direction.Backward;\n }\n play() {\n requestAnimationFrame(this.animate);\n }\n playForward() {\n this.direction = Direction.Forward;\n this.play();\n }\n playBackward() {\n this.direction = Direction.Backward;\n this.play();\n }\n stop() {\n this.direction = Direction.Stop;\n this.centerMarker = null;\n this.zoomMarker = null;\n this.prevTimestamp = null;\n this.elapsedTimeTotal = 0;\n }\n toggle() {\n this.isPlaying() ? this.stop() : this.play();\n }\n}\nexports.Animator = Animator;\nexports.default = new Animator();\n\n\n//# sourceURL=webpack://Timeline/./src/animator.ts?");
/***/ }),
/***/ "./src/api.ts":
/*!********************!*\
!*** ./src/api.ts ***!
\********************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst animator_1 = __webpack_require__(/*! ./animator */ \"./src/animator.ts\");\nconst constants_1 = __webpack_require__(/*! ./constants */ \"./src/constants.ts\");\nconst props_1 = __webpack_require__(/*! ./models/props */ \"./src/models/props.ts\");\nclass Api {\n constructor(rootElement, onChange) {\n this.onChange = onChange;\n this.animator = animator_1.default;\n this.handleChange = () => {\n const { from, to } = props_1.default.eventsBand;\n this.onChange({\n center: props_1.default.center,\n visibleFrom: from,\n visibleTo: to,\n });\n };\n document.addEventListener('keydown', (ev) => {\n if (ev.keyCode === 189)\n props_1.default.eventsBand.zoomOut();\n if (ev.keyCode === 187)\n props_1.default.eventsBand.zoomIn();\n });\n rootElement.addEventListener('wheel', (ev) => {\n if (Math.abs(ev.deltaX) === 0 && ev.deltaY !== 0) {\n if (ev.deltaY < 0)\n props_1.default.eventsBand.zoomOut();\n if (ev.deltaY > 0)\n props_1.default.eventsBand.zoomIn();\n }\n });\n if (this.onChange != null && typeof this.onChange === 'function') {\n document.addEventListener(constants_1.CENTER_CHANGE_DONE, this.handleChange);\n }\n }\n zoomIn() {\n props_1.default.eventsBand.zoomIn();\n }\n zoomOut() {\n props_1.default.eventsBand.zoomOut();\n this.handleChange();\n }\n}\nexports.default = Api;\n\n\n//# sourceURL=webpack://Timeline/./src/api.ts?");
/***/ }),
/***/ "./src/constants.ts":
/*!**************************!*\
!*** ./src/constants.ts ***!
\**************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.EVENT_MIN_SPACE = 160;\nexports.EVENT_HEIGHT = 14;\nexports.EVENT_ROW_HEIGHT = 20;\nexports.DATE_BAR_HEIGHT = exports.EVENT_ROW_HEIGHT;\nexports.RULER_LABELS_HEIGHT = 60;\nexports.CENTER_CHANGE_DONE = 'CENTER_CHANGE_DONE';\nclass RawSegment {\n}\nexports.RawSegment = RawSegment;\nexports.colors = [\n 'rgba(211,84,0',\n 'rgba(219,10,91',\n 'rgba(31,58,147',\n 'rgba(0,128,0'\n].map(color => (opacity = 1) => `${color},${opacity})`);\n\n\n//# sourceURL=webpack://Timeline/./src/constants.ts?");
/***/ }),
/***/ "./src/event-bus.ts":
/*!**************************!*\
!*** ./src/event-bus.ts ***!
\**************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nclass EventBus {\n constructor() {\n this.eventsListeners = [];\n }\n register(type, listener, target = document) {\n target.addEventListener(type, listener);\n this.eventsListeners.push([type, listener, target]);\n }\n flush() {\n this.eventsListeners.forEach((eventListener) => {\n const [type, listener, target] = eventListener;\n target.removeEventListener(type, listener);\n });\n this.eventsListeners = [];\n }\n}\nexports.EventBus = EventBus;\nexports.default = new EventBus();\n\n\n//# sourceURL=webpack://Timeline/./src/event-bus.ts?");
/***/ }),
/***/ "./src/index.ts":
/*!**********************!*\
!*** ./src/index.ts ***!
\**********************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst props_1 = __webpack_require__(/*! ./models/props */ \"./src/models/props.ts\");\nconst index_1 = __webpack_require__(/*! ./models/config/index */ \"./src/models/config/index.ts\");\nexports.TimelineConfig = index_1.default;\nconst band_1 = __webpack_require__(/*! ./views/band */ \"./src/views/band/index.ts\");\nconst create_element_1 = __webpack_require__(/*! ./utils/create-element */ \"./src/utils/create-element.ts\");\nconst utils_1 = __webpack_require__(/*! ./utils */ \"./src/utils/index.ts\");\nexports.calcPixelsPerMillisecond = utils_1.calcPixelsPerMillisecond;\nconst events_worker_1 = __webpack_require__(/*! ./utils/events.worker */ \"./src/utils/events.worker.ts\");\nexports.orderEvents = events_worker_1.orderEvents;\nexports.OrderedEvents = events_worker_1.OrderedEvents;\nconst api_1 = __webpack_require__(/*! ./api */ \"./src/api.ts\");\nconst events_1 = __webpack_require__(/*! ./views/band/events */ \"./src/views/band/events.ts\");\nconst canvas_1 = __webpack_require__(/*! ./views/canvas */ \"./src/views/canvas/index.ts\");\nconst label_1 = __webpack_require__(/*! ./views/label */ \"./src/views/label.ts\");\nclass Timeline extends api_1.default {\n constructor(config, onChange, onSelect) {\n super(config.rootElement, onChange);\n this.config = config;\n this.onSelect = onSelect;\n this.appendToWrapper = (child) => {\n let children = child.render();\n if (!Array.isArray(children))\n children = [children];\n children.forEach(c => this.wrapper.appendChild(c));\n };\n this.reload = (config) => {\n if (config != null)\n props_1.default.init(config);\n this.resize();\n };\n this.resize = () => {\n props_1.default.dimensions = this.config.rootElement;\n props_1.default.eventsBand.zoomLevel = props_1.default.eventsBand.zoomLevel;\n this.eventsBandView.resize();\n props_1.default.minimapBands.forEach(mmb => mmb.zoomLevel = mmb.zoomLevel);\n this.minimapBandViews.forEach(mmbv => mmbv.resize());\n this.animator.play();\n };\n props_1.default.init(config);\n config.rootElement.appendChild(this.render());\n const debouncedResize = utils_1.debounce(this.resize, 600);\n window.addEventListener('resize', debouncedResize);\n }\n render() {\n this.wrapper = create_element_1.default('div', 'wrapper', [\n 'box-sizing: border-box',\n 'height: 100%',\n 'overflow: hidden',\n 'position: relative',\n 'user-select: none',\n 'width: 100%',\n ]);\n this.appendToWrapper(new canvas_1.default());\n this.eventsBandView = new events_1.default(props_1.default.eventsBand, this.onSelect);\n this.appendToWrapper(this.eventsBandView);\n this.minimapBandViews = props_1.default.minimapBands.map(band => new band_1.default(band));\n this.minimapBandViews.forEach(this.appendToWrapper);\n this.renderLabels();\n return this.wrapper;\n }\n renderLabels() {\n props_1.default.eventsBand.domains\n .filter(d => d.label != null)\n .map(d => new label_1.default(d))\n .forEach(this.appendToWrapper);\n }\n}\nexports.default = Timeline;\n\n\n//# sourceURL=webpack://Timeline/./src/index.ts?");
/***/ }),
/***/ "./src/models/band/events.ts":
/*!***********************************!*\
!*** ./src/models/band/events.ts ***!
\***********************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst _1 = __webpack_require__(/*! . */ \"./src/models/band/index.ts\");\nconst animator_1 = __webpack_require__(/*! ../../animator */ \"./src/animator.ts\");\nconst constants_1 = __webpack_require__(/*! ../../constants */ \"./src/constants.ts\");\nconst props_1 = __webpack_require__(/*! ../props */ \"./src/models/props.ts\");\nclass EventsBand extends _1.default {\n constructor(config) {\n super(config);\n this.domains = config.domains;\n }\n getEventByCoordinates(x, y) {\n const timestamp = this.timestampAtProportion(this.proportionAtPosition(x));\n const domain = this.domains.find(d => {\n const top = props_1.default.viewportOffset + d.topOffsetRatio * props_1.default.viewportHeight;\n const height = props_1.default.viewportOffset + d.heightRatio * props_1.default.viewportHeight;\n return top < y && top + height > y;\n });\n const event = domain.orderedEvents.events.find(e => {\n if (!(e.from < timestamp && e.from + e.time + e.space > timestamp))\n return false;\n const bottomOfDomain = props_1.default.viewportOffset + ((domain.topOffsetRatio + domain.heightRatio) * props_1.default.viewportHeight) - constants_1.DATE_BAR_HEIGHT;\n const row = Math.floor((bottomOfDomain - y) / (constants_1.EVENT_HEIGHT + 2));\n return e.row === row;\n });\n return event;\n }\n zoomIn() {\n animator_1.default.zoomTo(this.zoomLevel + 1);\n }\n zoomOut() {\n animator_1.default.zoomTo(this.zoomLevel - 1);\n }\n}\nexports.default = EventsBand;\n\n\n//# sourceURL=webpack://Timeline/./src/models/band/events.ts?");
/***/ }),
/***/ "./src/models/band/index.ts":
/*!**********************************!*\
!*** ./src/models/band/index.ts ***!
\**********************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst dates_1 = __webpack_require__(/*! ../../utils/dates */ \"./src/utils/dates.ts\");\nconst props_1 = __webpack_require__(/*! ../props */ \"./src/models/props.ts\");\nconst utils_1 = __webpack_require__(/*! ../../utils */ \"./src/utils/index.ts\");\nconst animator_1 = __webpack_require__(/*! ../../animator */ \"./src/animator.ts\");\nclass Band {\n constructor(config) {\n this.defaultZoomLevel = 0;\n this.update = () => {\n const offset = props_1.default.center * (props_1.default.time - this.time);\n this.from = props_1.default.from + offset;\n this.to = this.from + this.time;\n this.left = Math.round(props_1.default.center * (props_1.default.viewportWidth - this.width));\n };\n this.zoomLevel = config.zoomLevel;\n this.height = Math.round(config.domains.reduce((prev, curr) => prev + curr.heightRatio, 0) * props_1.default.viewportHeight);\n this.top = Math.round(config.domains.reduce((prev, curr) => Math.min(prev, curr.topOffsetRatio), 1) * props_1.default.viewportHeight);\n animator_1.default.registerModelUpdaters(this.update);\n }\n get left() { return this._left; }\n set left(left) {\n if (left < -this.width + props_1.default.viewportWidth)\n left = props_1.default.viewportWidth - this.width;\n else if (left > 0)\n left = 0;\n this._left = left;\n }\n get zoomLevel() { return this._zoomLevel; }\n set zoomLevel(zoomLevel) {\n if (zoomLevel < 0)\n zoomLevel = 0;\n this.visibleRatio = utils_1.visibleRatio(zoomLevel);\n this.width = Math.round(props_1.default.viewportWidth / this.visibleRatio);\n this.time = this.visibleRatio * props_1.default.time;\n this.update();\n this.granularity = dates_1.getGranularity(props_1.default.from, props_1.default.to, this.visibleRatio);\n this.nextDate = dates_1.subsequentDate(this.granularity);\n this.pixelsPerMillisecond = this.width / props_1.default.time;\n this._zoomLevel = zoomLevel;\n }\n positionAtTimestamp(date) {\n return Math.round((date - props_1.default.from) * this.pixelsPerMillisecond);\n }\n proportionAtPosition(position) {\n return (Math.abs(this.left) + position) / this.width;\n }\n timestampAtProportion(proportion) {\n return props_1.default.from + (props_1.default.time * proportion);\n }\n}\nexports.default = Band;\n\n\n//# sourceURL=webpack://Timeline/./src/models/band/index.ts?");
/***/ }),
/***/ "./src/models/band/minimap.ts":
/*!************************************!*\
!*** ./src/models/band/minimap.ts ***!
\************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst _1 = __webpack_require__(/*! . */ \"./src/models/band/index.ts\");\nclass MinimapBand extends _1.default {\n constructor(config) {\n super(config);\n this.config = config;\n this.domains = config.domains;\n }\n}\nexports.default = MinimapBand;\n\n\n//# sourceURL=webpack://Timeline/./src/models/band/minimap.ts?");
/***/ }),
/***/ "./src/models/config/index.ts":
/*!************************************!*\
!*** ./src/models/config/index.ts ***!
\************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nclass DomainConfig {\n constructor() {\n this.heightRatio = 1;\n this.rulers = true;\n this.rulerLabels = true;\n this.topOffsetRatio = 0;\n }\n}\nexports.DomainConfig = DomainConfig;\nclass MinimapDomainConfig extends DomainConfig {\n constructor() {\n super(...arguments);\n this.targets = [];\n }\n}\nexports.MinimapDomainConfig = MinimapDomainConfig;\nclass EventsDomainConfig extends DomainConfig {\n}\nexports.EventsDomainConfig = EventsDomainConfig;\nclass BandConfig {\n constructor() {\n this.domains = [];\n this.zoomLevel = 0;\n }\n}\nexports.BandConfig = BandConfig;\nclass Config {\n constructor() {\n this.center = .5;\n this.minimaps = [];\n }\n}\nexports.default = Config;\n\n\n//# sourceURL=webpack://Timeline/./src/models/config/index.ts?");
/***/ }),
/***/ "./src/models/props.ts":
/*!*****************************!*\
!*** ./src/models/props.ts ***!
\*****************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst constants_1 = __webpack_require__(/*! ../constants */ \"./src/constants.ts\");\nconst minimap_1 = __webpack_require__(/*! ./band/minimap */ \"./src/models/band/minimap.ts\");\nconst events_1 = __webpack_require__(/*! ./band/events */ \"./src/models/band/events.ts\");\nconst utils_1 = __webpack_require__(/*! ../utils */ \"./src/utils/index.ts\");\nconst prepare_config_1 = __webpack_require__(/*! ../utils/prepare-config */ \"./src/utils/prepare-config.ts\");\nconst dates_1 = __webpack_require__(/*! ../utils/dates */ \"./src/utils/dates.ts\");\nclass Props {\n constructor() {\n this.defaultCenter = .5;\n this._center = this.defaultCenter;\n this.centerChangeDone = utils_1.debounce(() => {\n document.dispatchEvent(new CustomEvent(constants_1.CENTER_CHANGE_DONE));\n }, 300);\n }\n init(config) {\n if (config.rootElement == null)\n console.error('[init] No rootElement found');\n this.dimensions = config.rootElement;\n const froms = [];\n const tos = [];\n for (const domain of config.events.domains) {\n let events;\n if (domain.hasOwnProperty('events')) {\n domain.events.sort(dates_1.byDate);\n events = domain.events;\n }\n if (events == null)\n events = domain.orderedEvents.events;\n froms.push(events[0].date_min || events[0].date);\n tos.push(events.reduce((prev, curr) => {\n return Math.max(prev, curr.end_date || -Infinity, curr.end_date_max || -Infinity);\n }, -Infinity));\n }\n this.from = Math.min(...froms);\n this.to = Math.max(...tos);\n const pixelsPerMillisecond = utils_1.calcPixelsPerMillisecond(this.viewportWidth, config.events.zoomLevel || 0, this.to - this.from);\n config = prepare_config_1.default(config, pixelsPerMillisecond);\n this.time = this.to - this.from;\n if (config.center != null)\n this.center = config.center;\n this.minimapBands = config.minimaps.map(mm => new minimap_1.default(mm));\n this.eventsBand = new events_1.default(config.events);\n }\n get center() { return this._center; }\n set center(n) {\n if ((this._center === 0 && n < 0) || (this._center === 1 && n > 1))\n return;\n else if (n < 0)\n this._center = 0;\n else if (n > 1)\n this._center = 1;\n else\n this._center = n;\n this.centerChangeDone();\n }\n set dimensions(rootElement) {\n const style = getComputedStyle(rootElement);\n this.viewportHeight = parseInt(style.getPropertyValue('height'), 10);\n this.viewportOffset = rootElement.getBoundingClientRect().top;\n this.viewportWidth = parseInt(style.getPropertyValue('width'), 10);\n }\n}\nexports.Props = Props;\nexports.default = new Props();\n\n\n//# sourceURL=webpack://Timeline/./src/models/props.ts?");
/***/ }),
/***/ "./src/utils/create-element.ts":
/*!*************************************!*\
!*** ./src/utils/create-element.ts ***!
\*************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.createSvg = (name, style, attrs = {}) => {\n const el = document.createElementNS(\"http://www.w3.org/2000/svg\", name);\n if (style != null)\n el.setAttribute('style', style.join(';').concat(';'));\n Object.keys(attrs).forEach(k => el.setAttribute(k, attrs[k]));\n return el;\n};\nlet sheet;\nif (typeof window !== 'undefined') {\n const element = document.createElement('style');\n document.head.appendChild(element);\n sheet = element.sheet;\n}\nconst rules = {};\nexports.default = (name, className, style, dynamicStyle) => {\n if (!className)\n return document.createElement(name);\n let el;\n if (rules.hasOwnProperty(className)) {\n el = rules[className].cloneNode(false);\n }\n else {\n el = document.createElement(name);\n el.classList.add(className);\n if (style) {\n sheet.insertRule(`.${className} { ${style.join(';').concat(';')} }`);\n }\n rules[className] = el.cloneNode(false);\n }\n if (dynamicStyle)\n el.setAttribute('style', dynamicStyle.join(';').concat(';'));\n return el;\n};\n\n\n//# sourceURL=webpack://Timeline/./src/utils/create-element.ts?");
/***/ }),
/***/ "./src/utils/dates.ts":
/*!****************************!*\
!*** ./src/utils/dates.ts ***!
\****************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.isEqual = (date1, date2) => date1.getTime() === date2.getTime();\nexports.format = (date, granularity) => {\n if (date == null)\n return '∞';\n let displayDate = date.getFullYear().toString();\n if (granularity >= 3) {\n const months = [\n 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\n 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',\n ];\n displayDate = `${months[date.getMonth()]} ${displayDate}`;\n }\n if (granularity >= 1) {\n displayDate = `${date.getDate()} ${displayDate}`;\n }\n if (granularity === 0) {\n displayDate = `${date.getHours()}:${date.getMinutes()} ${displayDate}`;\n }\n return displayDate;\n};\nexports.getGranularity = (from, to, visibleRatio) => {\n const days = visibleRatio * ((to - from) / 86400000);\n if (days < 1)\n return 0;\n if (days < 15)\n return 1;\n if (days < 45)\n return 2;\n if (days < 1.5 * 365)\n return 3;\n if (days < 15 * 365)\n return 4;\n if (days < 100 * 365)\n return 5;\n if (days < 200 * 365)\n return 6;\n if (days < 400 * 365)\n return 7;\n if (days < 3000 * 365)\n return 8;\n if (days < 6000 * 365)\n return 9;\n return 10;\n};\nexports.getStep = (granularity) => {\n if (granularity === 4)\n return 1;\n if (granularity === 5)\n return 5;\n if (granularity === 6)\n return 10;\n if (granularity === 7)\n return 50;\n if (granularity === 8)\n return 100;\n if (granularity === 9)\n return 500;\n if (granularity === 10)\n return 1000;\n throw new RangeError(\"[getStep] Only steps with a granularity greater than 'year' calculated\");\n};\nfunction subsequentDate(granularity) {\n if (granularity >= 4) {\n const step = exports.getStep(granularity);\n return (d) => {\n let date = new Date(d);\n const nextYear = date.getFullYear() + step;\n if (nextYear > -1 && nextYear < 100) {\n date = new Date(date);\n date.setUTCFullYear(nextYear);\n return date.getTime();\n }\n else {\n return Date.UTC(nextYear, 0, 1);\n }\n };\n }\n if (granularity === 3) {\n return (d) => {\n const date = new Date(d);\n return Date.UTC(date.getFullYear(), date.getMonth() + 1, 1);\n };\n }\n if (granularity === 2) {\n return (d) => {\n const date = new Date(d);\n return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate() + 7);\n };\n }\n if (granularity === 1) {\n return (d) => {\n const date = new Date(d);\n return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate() + 1);\n };\n }\n if (granularity === 0) {\n return (d) => {\n const date = new Date(d);\n return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours() + 1);\n };\n }\n}\nexports.subsequentDate = subsequentDate;\nfunction byDate(a, b) {\n const aFrom = a.date_min != null ? a.date_min : a.date;\n const bFrom = b.date_min != null ? b.date_min : b.date;\n if (aFrom < bFrom)\n return -1;\n if (aFrom > bFrom)\n return 1;\n const aTo = a.end_date_max != null ? a.end_date_max : a.end_date;\n const bTo = b.end_date_max != null ? b.end_date_max : b.end_date;\n if (aTo < bTo)\n return -1;\n if (aTo > bTo)\n return 1;\n return 0;\n}\nexports.byDate = byDate;\nconst days = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\nconst months = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\nconst getWeekNumber = (date) => {\n const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));\n const dayNum = d.getUTCDay() || 7;\n d.setUTCDate(d.getUTCDate() + 4 - dayNum);\n const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n return Math.ceil((((d.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);\n};\nexports.labelBody = (d, granularity) => {\n const date = new Date(d);\n if (granularity >= 4) {\n return date.getUTCFullYear().toString();\n }\n else if (granularity === 3) {\n let body = months[date.getUTCMonth()];\n if (date.getUTCMonth() === 0)\n body = `${date.getUTCFullYear().toString()}, ${body}`;\n return body;\n }\n else if (granularity === 2) {\n return `${months[date.getUTCMonth()]}, week ${getWeekNumber(date)}`;\n }\n else if (granularity === 1) {\n let body = days[date.getUTCDay()];\n body = `${body}, ${months[date.getUTCMonth()]} ${date.getUTCDate()}`;\n if (date.getUTCMonth() === 0 && date.getUTCDate() === 1)\n body = `${body}, ${date.getUTCFullYear().toString()}`;\n return body;\n }\n else if (granularity === 0) {\n return `${date.getUTCHours()}:00`;\n }\n};\n\n\n//# sourceURL=webpack://Timeline/./src/utils/dates.ts?");
/***/ }),
/***/ "./src/utils/events.worker.ts":
/*!************************************!*\
!*** ./src/utils/events.worker.ts ***!
\************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst constants_1 = __webpack_require__(/*! ../constants */ \"./src/constants.ts\");\nclass OrderedEvents {\n constructor() {\n this.events = [];\n this.grid = [];\n this.rowCount = 0;\n }\n}\nexports.OrderedEvents = OrderedEvents;\nconst pixelsPerLetter = 8;\nfunction orderEvents(events, pixelsPerMillisecond) {\n if (!events.length)\n return new OrderedEvents();\n let rowCount = 0;\n const grid = [];\n const paddingRight = constants_1.EVENT_HEIGHT * 2 / pixelsPerMillisecond;\n const addRow = (event) => {\n let row;\n event.from = event.date_min || event.date;\n event.to = event.end_date_max || event.end_date;\n event.time = event.to == null ? 0 : event.to - event.from;\n event.space = 0;\n if (!event.time) {\n if (event.label == null)\n event.label = 'NO LABEL';\n event.space = ((event.label.length * pixelsPerLetter) / pixelsPerMillisecond) + paddingRight;\n }\n let rowIterator = 0;\n while (row == null && rowIterator < grid.length) {\n let cellIterator = 0;\n let hasSpace = true;\n while (hasSpace && cellIterator < grid[rowIterator].length) {\n if (event.to < grid[rowIterator][cellIterator][0])\n break;\n hasSpace = event.from > grid[rowIterator][cellIterator][1];\n cellIterator++;\n }\n if (hasSpace) {\n grid[rowIterator].push([event.from, event.from + event.time + event.space]);\n row = rowIterator;\n }\n rowIterator++;\n }\n if (row == null)\n row = grid.push([[event.from, event.from + event.time + event.space]]) - 1;\n if (row > rowCount)\n rowCount = row;\n event.row = row;\n return event;\n };\n events = events.map(addRow);\n return {\n events,\n grid,\n rowCount\n };\n}\nexports.orderEvents = orderEvents;\nfunction eventsWorker(e) {\n importScripts(e.data.orderEventsURL);\n postMessage(orderEvents(e.data.events));\n}\nexports.eventsWorker = eventsWorker;\nexports.default = (events, done) => {\n const orderEventsURL = URL.createObjectURL(new Blob([orderEvents]));\n const func = `onmessage = ${eventsWorker.toString()}`;\n const objectURL = URL.createObjectURL(new Blob([func]));\n let worker = new Worker(objectURL);\n worker.postMessage({ events, orderEventsURL });\n worker.onmessage = (e) => {\n URL.revokeObjectURL(objectURL);\n worker.terminate();\n done(e.data);\n };\n};\n\n\n//# sourceURL=webpack://Timeline/./src/utils/events.worker.ts?");
/***/ }),
/***/ "./src/utils/index.ts":
/*!****************************!*\
!*** ./src/utils/index.ts ***!
\****************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst dates_1 = __webpack_require__(/*! ./dates */ \"./src/utils/dates.ts\");\nexports.debounce = (func, wait) => {\n let timeout;\n return () => {\n clearTimeout(timeout);\n timeout = setTimeout(func, wait);\n };\n};\nexports.onVisible = (from, to) => (e) => {\n const eventFrom = e.date_min || e.date;\n let eventTo = e.end_date_max || e.end_date;\n if (eventTo == null)\n eventTo = eventFrom;\n if (eventFrom == null && eventTo == null)\n return false;\n return !(eventTo < from || eventFrom > to);\n};\nfunction findClosestRulerDate(timestamp, granularity) {\n if (timestamp == null || isNaN(timestamp)) {\n console.error('[findClosestRulerDate] start timestamp is not defined');\n return;\n }\n const date = new Date(timestamp);\n let year = date.getUTCFullYear();\n if (granularity >= 4) {\n const step = dates_1.getStep(granularity);\n if (granularity === 4)\n year += 1;\n else\n while (year % step !== 0) {\n year += 1;\n }\n if (year > -1 && year < 100) {\n const nextDate = new Date(Date.UTC(year, 0, 1));\n nextDate.setUTCFullYear(year);\n return nextDate.getTime();\n }\n else {\n return Date.UTC(year, 0, 1);\n }\n }\n else if (granularity === 3) {\n return Date.UTC(year, date.getUTCMonth() + 1, 1);\n }\n else if (granularity === 1) {\n return Date.UTC(year, date.getUTCMonth(), date.getUTCDate() + 1);\n }\n else if (granularity === 0) {\n return Date.UTC(year, date.getUTCMonth(), date.getUTCDate(), date.getUTCHours() + 1);\n }\n return timestamp;\n}\nexports.findClosestRulerDate = findClosestRulerDate;\nfunction visibleRatio(zoomLevel) {\n return Math.pow(2, zoomLevel * -1);\n}\nexports.visibleRatio = visibleRatio;\nfunction createRange(n) {\n return Array.apply(null, { length: n }).map(Number.call, Number);\n}\nexports.createRange = createRange;\nfunction selectRandom(set, amount) {\n const selected = [];\n while (selected.length < amount) {\n const randomIndex = Math.floor(Math.random() * set.length);\n const nextItem = set[randomIndex];\n if (selected.indexOf(nextItem) === -1 || set.length < amount)\n selected.push(nextItem);\n }\n return selected;\n}\nexports.selectRandom = selectRandom;\nfunction calcPixelsPerMillisecond(viewportWidth, zoomLevel, totalTime) {\n return (viewportWidth / visibleRatio(zoomLevel)) / totalTime;\n}\nexports.calcPixelsPerMillisecond = calcPixelsPerMillisecond;\n\n\n//# sourceURL=webpack://Timeline/./src/utils/index.ts?");
/***/ }),
/***/ "./src/utils/prepare-config.ts":
/*!*************************************!*\
!*** ./src/utils/prepare-config.ts ***!
\*************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst config_1 = __webpack_require__(/*! ../models/config */ \"./src/models/config/index.ts\");\nconst events_worker_1 = __webpack_require__(/*! ./events.worker */ \"./src/utils/events.worker.ts\");\nfunction prepareConfig(config, pixelsPerMillisecond) {\n if (config.events == null) {\n console.error('[DomainConfig] No events band in config!');\n return config;\n }\n if (config.events.domains == null || !config.events.domains.length) {\n console.error('[DomainConfig] No events band domains in config!');\n return config;\n }\n config.events.domains = config.events.domains.map(domainConfig => {\n if (domainConfig.events == null && domainConfig.orderedEvents == null) {\n console.error('[DomainConfig] No events in config!');\n }\n else if (domainConfig.orderedEvents == null) {\n domainConfig.orderedEvents = events_worker_1.orderEvents(domainConfig.events, pixelsPerMillisecond);\n delete domainConfig.events;\n }\n return Object.assign({}, new config_1.EventsDomainConfig(), domainConfig);\n });\n config = Object.assign({}, new config_1.default(), config);\n config.events.domains = config.events.domains.map(d => (Object.assign({}, new config_1.EventsDomainConfig(), d)));\n config.events = Object.assign({}, new config_1.BandConfig(), config.events);\n config.minimaps = config.minimaps.map(mm => {\n mm = Object.assign({}, new config_1.BandConfig(), mm);\n if (!mm.domains.length)\n mm.domains.push({});\n mm.domains = mm.domains.map(d => (Object.assign({}, new config_1.MinimapDomainConfig(), d)));\n return (Object.assign({}, new config_1.BandConfig(), mm));\n });\n return config;\n}\nexports.default = prepareConfig;\n\n\n//# sourceURL=webpack://Timeline/./src/utils/prepare-config.ts?");
/***/ }),
/***/ "./src/views/band/events.ts":
/*!**********************************!*\
!*** ./src/views/band/events.ts ***!
\**********************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst index_1 = __webpack_require__(/*! ./index */ \"./src/views/band/index.ts\");\nconst event_bus_1 = __webpack_require__(/*! ../../event-bus */ \"./src/event-bus.ts\");\nfunction formatDate(ts) {\n const d = new Date(ts);\n return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;\n}\nclass EventsBandView extends index_1.default {\n constructor(band, select) {\n super(band);\n this.band = band;\n this.select = select;\n this.onClick = (ev) => {\n const event = this.band.getEventByCoordinates(ev.clientX, ev.clientY);\n if (event && this.select) {\n this.select(event);\n console.log(event, formatDate(event.from), formatDate(event.to));\n }\n };\n }\n render() {\n const root = super.render();\n event_bus_1.default.register('click', this.onClick, this.rootElement);\n return root;\n }\n}\nexports.default = EventsBandView;\n\n\n//# sourceURL=webpack://Timeline/./src/views/band/events.ts?");
/***/ }),
/***/ "./src/views/band/index.ts":
/*!*********************************!*\
!*** ./src/views/band/index.ts ***!
\*********************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst props_1 = __webpack_require__(/*! ../../models/props */ \"./src/models/props.ts\");\nconst create_element_1 = __webpack_require__(/*! ../../utils/create-element */ \"./src/utils/create-element.ts\");\nconst event_bus_1 = __webpack_require__(/*! ../../event-bus */ \"./src/event-bus.ts\");\nconst animator_1 = __webpack_require__(/*! ../../animator */ \"./src/animator.ts\");\nclass BandView {\n constructor(band) {\n this.band = band;\n this.onMouseDown = (ev) => {\n document.addEventListener('mouseup', this.onMouseUp);\n this.dragOffset = ev.clientX;\n this.dragStart = this.band.left;\n };\n this.onMouseMove = (ev) => {\n if (this.dragOffset && this.band.zoomLevel > 0) {\n const left = this.dragStart - (this.dragOffset - ev.clientX);\n props_1.default.center = left / (props_1.default.viewportWidth - this.band.width);\n animator_1.default.play();\n }\n };\n this.onMouseUp = (ev) => {\n this.dragOffset = null;\n document.removeEventListener('mouseup', this.onMouseUp);\n };\n this.onDblClick = (ev) => {\n const nextCenter = this.band.proportionAtPosition(ev.clientX);\n animator_1.default.goTo(nextCenter);\n };\n }\n render() {\n this.rootElement = create_element_1.default('div', 'band-wrap', [\n 'position: absolute',\n 'z-index: 1',\n ], [\n `height: ${this.band.height}px`,\n `top: ${this.band.top}px`,\n `width: ${props_1.default.viewportWidth}px`,\n ]);\n if (this.band.zoomLevel > 0) {\n event_bus_1.default.register('mousedown', this.onMouseDown, this.rootElement);\n event_bus_1.default.register('mousemove', this.onMouseMove, this.rootElement);\n }\n event_bus_1.default.register('dblclick', this.onDblClick, this.rootElement);\n return this.rootElement;\n }\n resize() {\n this.rootElement.style.cssText = `height: ${this.band.height}px; top: ${this.band.top}px; width: ${props_1.default.viewportWidth}px;`;\n }\n}\nexports.default = BandView;\n\n\n//# sourceURL=webpack://Timeline/./src/views/band/index.ts?");
/***/ }),
/***/ "./src/views/canvas/index.ts":
/*!***********************************!*\
!*** ./src/views/canvas/index.ts ***!
\***********************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst create_element_1 = __webpack_require__(/*! ../../utils/create-element */ \"./src/utils/create-element.ts\");\nconst props_1 = __webpack_require__(/*! ../../models/props */ \"./src/models/props.ts\");\nconst constants_1 = __webpack_require__(/*! ../../constants */ \"./src/constants.ts\");\nconst utils_1 = __webpack_require__(/*! ../../utils */ \"./src/utils/index.ts\");\nconst dates_1 = __webpack_require__(/*! ../../utils/dates */ \"./src/utils/dates.ts\");\nconst animator_1 = __webpack_require__(/*! ../../animator */ \"./src/animator.ts\");\nclass Canvas {\n constructor() {\n this.font = \"10px sans-serif\";\n this.offsiteCanvas = create_element_1.default('canvas');\n this.clear = () => {\n this.ctx.clearRect(props_1.default.eventsBand.top, 0, this.canvas.width, props_1.default.eventsBand.height);\n props_1.default.minimapBands\n .filter(band => band.zoomLevel !== 0)\n .forEach(band => this.ctx.clearRect(0, band.top, this.canvas.width, band.height));\n };\n this.update = () => {\n if (this.canvas.width !== props_1.default.viewportWidth || this.canvas.height !== props_1.default.viewportHeight) {\n this.canvas.width = props_1.default.viewportWidth;\n this.canvas.height = props_1.default.viewportHeight;\n this.indicatorsCanvas.width = props_1.default.viewportWidth;\n this.indicatorsCanvas.height = props_1.default.viewportHeight;\n this.drawStaticMinimapBands();\n }\n this.clear();\n this.drawRulers(props_1.default.eventsBand);\n this.drawEvents();\n props_1.default.minimapBands\n .filter(band => band.zoomLevel !== 0)\n .forEach(band => {\n band.domains.forEach(domain => {\n this.drawMinimap(band, domain);\n });\n this.drawRulers(band);\n });\n this.drawIndicators();\n };\n animator_1.default.registerViewUpdaters(this.update);\n this.offsiteCtx = this.offsiteCanvas.getContext('2d');\n }\n render() {\n this.canvas = create_element_1.default('canvas', 'minimap', [\n 'position: absolute',\n ]);\n this.canvas.width = props_1.default.viewportWidth;\n this.canvas.height = props_1.default.viewportHeight;\n this.ctx = this.canvas.getContext('2d');\n this.ctx.font = this.font;\n this.indicatorsCanvas = create_element_1.default('canvas', 'minimap', [\n 'position: absolute',\n ], ['z-index: 1']);\n this.indicatorsCanvas.width = props_1.default.viewportWidth;\n this.indicatorsCanvas.height = props_1.default.viewportHeight;\n this.indicatorsCtx = this.indicatorsCanvas.getContext('2d');\n this.update();\n this.drawStaticMinimapBands();\n return [this.canvas, this.indicatorsCanvas];\n }\n drawStaticMinimapBands() {\n props_1.default.minimapBands\n .filter(band => band.zoomLevel === 0)\n .forEach(band => {\n band.domains.forEach(domain => {\n this.drawMinimap(band, domain);\n });\n this.drawRulers(band);\n });\n }\n drawEvents() {\n this.ctx.beginPath();\n props_1.default.eventsBand.domains.forEach(domain => {\n const band = props_1.default.eventsBand;\n const left = band.positionAtTimestamp(band.from);\n const offsetY = domain.topOffsetRatio * props_1.default.viewportHeight;\n const domainHeight = (domain.heightRatio * props_1.default.viewportHeight) - constants_1.DATE_BAR_HEIGHT;\n for (const event of domain.orderedEvents.events) {\n event.left = band.positionAtTimestamp(event.from) - left;\n event.width = Math.round((event.time + event.space) * band.pixelsPerMillisecond);\n if (event.width < 1)\n event.width = 1;\n event.top = offsetY + domainHeight - ((event.row + 1) * (constants_1.EVENT_HEIGHT + 2));\n if (event.from > band.to || event.to < band.from)\n continue;\n if (!event.time) {\n this.ctx.moveTo(event.left, event.top + constants_1.EVENT_HEIGHT / 2);\n this.ctx.arc(event.left, event.top + constants_1.EVENT_HEIGHT / 2, constants_1.EVENT_HEIGHT / 3, 0, 2 * Math.PI);\n }\n else {\n this.ctx.rect(event.left, event.top, event.width, constants_1.EVENT_HEIGHT);\n }\n }\n });\n this.ctx.fillStyle = `rgba(126, 0, 0, .3)`;\n this.ctx.fill();\n this.drawEventsText();\n }\n drawEventsText() {\n this.ctx.fillStyle = `rgb(126, 0, 0)`;\n for (const domain of props_1.default.eventsBand.domains) {\n for (const event of domain.orderedEvents.events) {\n if (event.from > props_1.default.eventsBand.to || event.to < props_1.default.eventsBand.from)\n continue;\n let eventWidth = event.width;\n let eventLeft = event.left;\n if (event.left < 0 && event.time !== 0) {\n eventWidth = event.width + event.left;\n eventLeft = 0;\n }\n if (event.label == null)\n event.label = 'NO LABEL';\n if ((event.label.length * 8) + 10 < eventWidth) {\n const paddingLeft = event.time ? 3 : 8;\n this.ctx.fillText(event.label, eventLeft + paddingLeft, event.top + constants_1.EVENT_HEIGHT - 3);\n }\n }\n }\n }\n drawMinimap(band, domain) {\n const maxHeight = band.height - constants_1.DATE_BAR_HEIGHT;\n const maxRowCount = band.domains.reduce((prev, curr) => {\n const counts = curr.targets.map(index => props_1.default.eventsBand.domains[index].orderedEvents.rowCount);\n return Math.max(prev, ...counts);\n }, 0);\n let eventHeight = maxHeight / maxRowCount;\n if (eventHeight < 1) {\n eventHeight = 1;\n this.offsiteCanvas.width = props_1.default.viewportWidth;\n this.offsiteCanvas.height = maxRowCount;\n drawEvents(this.offsiteCtx, maxRowCount, 0);\n this.ctx.drawImage(this.offsiteCanvas, 0, band.top, props_1.default.viewportWidth, maxHeight);\n }\n else {\n eventHeight = Math.round(eventHeight);\n drawEvents(this.ctx, maxHeight);\n }\n function drawEvents(ctx, height, offsetY = band.top) {\n ctx.beginPath();\n const left = band.positionAtTimestamp(band.from);\n domain.targets.forEach(targetIndex => {\n const targetDomain = props_1.default.eventsBand.domains[targetIndex];\n for (const event of targetDomain.orderedEvents.events) {\n if (event.from > band.to || event.to < band.from)\n continue;\n const eventWidth = Math.round(event.time * band.pixelsPerMillisecond);\n const eventLeft = band.positionAtTimestamp(event.date_min != null ? event.date_min : event.date);\n const y = offsetY + height - ((event.row + 1) * eventHeight);\n const width = eventWidth < 1 ? 1 : eventWidth;\n ctx.rect(eventLeft - left, y, width, eventHeight);\n }\n });\n ctx.fillStyle = `rgba(0, 0, 0, .2)`;\n ctx.fill();\n }\n }\n drawIndicators() {\n this.indicatorsCtx.clearRect(0, 0, props_1.default.viewportWidth, props_1.default.viewportHeight);\n this.indicatorsCtx.beginPath();\n props_1.default.minimapBands.forEach(band => {\n band.domains.forEach(domain => {\n const indicatorTOP = Math.round(domain.topOffsetRatio * props_1.default.viewportHeight);\n const leftIndicatorRightX = band.positionAtTimestamp(props_1.default.eventsBand.from) + band.left;\n this.indicatorsCtx.rect(0, indicatorTOP, leftIndicatorRightX, band.height);\n const rightIndicatorLeftX = band.positionAtTimestamp(props_1.default.eventsBand.to) + band.left;\n this.indicatorsCtx.rect(rightIndicatorLeftX, indicatorTOP, props_1.default.viewportWidth, band.height);\n this.indicatorsCtx.rect(leftIndicatorRightX, indicatorTOP + band.height - constants_1.DATE_BAR_HEIGHT, rightIndicatorLeftX - leftIndicatorRightX, constants_1.DATE_BAR_HEIGHT);\n });\n });\n this.indicatorsCtx.fillStyle = `rgba(0, 0, 0, .1)`;\n this.indicatorsCtx.fill();\n this.indicatorsCtx.fillStyle = `rgba(255, 0, 0, .5)`;\n const x = props_1.default.eventsBand.positionAtTimestamp(props_1.default.eventsBand.timestampAtProportion(props_1.default.center)) + props_1.default.eventsBand.left;\n this.indicatorsCtx.fillRect(x - 1, 0, 2, props_1.default.viewportHeight);\n this.indicatorsCtx.closePath();\n }\n drawRulers(band) {\n this.ctx.beginPath();\n this.ctx.fillStyle = `rgb(150, 150, 150)`;\n for (const domain of band.domains) {\n if (!domain.rulers)\n continue;\n let date = utils_1.findClosestRulerDate(band.from, band.granularity);\n const y = domain.topOffsetRatio * props_1.default.viewportHeight;\n const height = domain.heightRatio * props_1.default.viewportHeight;\n while (date < band.to) {\n const left = band.positionAtTimestamp(date) + band.left;\n this.ctx.moveTo(left, y);\n this.ctx.lineTo(left, y + height);\n if (domain.rulerLabels)\n this.ctx.fillText(dates_1.labelBody(date, band.granularity), left + 3, y + height - 3);\n date = band.nextDate(date);\n }\n }\n this.ctx.strokeStyle = `rgb(200, 200, 200)`;\n this.ctx.stroke();\n }\n}\nexports.default = Canvas;\n\n\n//# sourceURL=webpack://Timeline/./src/views/canvas/index.ts?");
/***/ }),
/***/ "./src/views/label.ts":
/*!****************************!*\
!*** ./src/views/label.ts ***!
\****************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst create_element_1 = __webpack_require__(/*! ../utils/create-element */ \"./src/utils/create-element.ts\");\nclass Label {\n constructor(domain) {\n this.domain = domain;\n }\n render() {\n const wrapper = create_element_1.default('div', 'events-label-wrapper', [\n 'border-top: 1px solid #CCC',\n 'position: absolute',\n 'width: 100%',\n ], [\n `top: ${this.domain.topOffsetRatio * 100}%`\n ]);\n const eventsLabel = create_element_1.default('div', 'events-label', [\n 'background: white',\n 'border-bottom-right-radius: 4px',\n 'box-shadow: 1px 2px 4px #AAA',\n 'display: inline-block',\n 'color: #444',\n 'font-size: .8em',\n 'font-family: sans-serif',\n 'padding: 4px 8px',\n ]);\n eventsLabel.innerText = this.domain.label;\n wrapper.appendChild(eventsLabel);\n return wrapper;\n }\n}\nexports.default = Label;\n\n\n//# sourceURL=webpack://Timeline/./src/views/label.ts?");
/***/ })
/******/ });
});
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Timeline=e():t.Timeline=e()}(this,function(){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var s=e[n]={i:n,l:!1,exports:{}};return t[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=t,i.c=e,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var s in t)i.d(n,s,function(e){return t[e]}.bind(null,s));return n},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="/build/",i(i.s=0)}([function(t,e,i){"use strict";i.r(e);const n=14,s=20,o="CENTER_CHANGE_DONE",r="ZOOM_DONE",a=8;["rgba(211,84,0","rgba(219,10,91","rgba(31,58,147","rgba(0,128,0"].map(t=>(e=1)=>`${t},${e})`);const h=(t,e,i)=>{const n=i*((e-t)/864e5);return n<1?0:n<15?1:n<45?2:n<547.5?3:n<5475?4:n<36500?5:n<73e3?6:n<146e3?7:n<1095e3?8:n<219e4?9:10},l=t=>{if(4===t)return 1;if(5===t)return 5;if(6===t)return 10;if(7===t)return 50;if(8===t)return 100;if(9===t)return 500;if(10===t)return 1e3;throw new RangeError("[getStep] Only steps with a granularity greater than 'year' calculated")};function d(t,e){const i=null!=t.date_min?t.date_min:t.date,n=null!=e.date_min?e.date_min:e.date;if(i<n)return-1;if(i>n)return 1;const s=null!=t.end_date_max?t.end_date_max:t.end_date,o=null!=e.end_date_max?e.end_date_max:e.end_date;return s<o?-1:s>o?1:0}const c=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],u=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],m=(t,e)=>{const i=new Date(t);if(e>=4)return i.getUTCFullYear().toString();if(3===e){let t=u[i.getUTCMonth()];return 0===i.getUTCMonth()&&(t=`${i.getUTCFullYear().toString()}, ${t}`),t}if(2===e)return`${u[i.getUTCMonth()]}, week ${(t=>{const e=new Date(Date.UTC(t.getFullYear(),t.getMonth(),t.getDate())),i=e.getUTCDay()||7;e.setUTCDate(e.getUTCDate()+4-i);const n=new Date(Date.UTC(e.getUTCFullYear(),0,1));return Math.ceil(((e.getTime()-n.getTime())/864e5+1)/7)})(i)}`;if(1===e){let t=c[i.getUTCDay()];return t=`${t}, ${u[i.getUTCMonth()]} ${i.getUTCDate()}`,0===i.getUTCMonth()&&1===i.getUTCDate()&&(t=`${t}, ${i.getUTCFullYear().toString()}`),t}return 0===e?`${i.getUTCHours()}:00`:void 0},p=(t,e)=>{let i;return()=>{clearTimeout(i),i=setTimeout(t,e)}};function f(t,e){if(null==t||isNaN(t))return void console.error("[findClosestRulerDate] start timestamp is not defined");const i=new Date(t);let n=i.getUTCFullYear();if(e>=4){const t=l(e);if(4===e)n+=1;else for(;n%t!=0;)n+=1;if(n>-1&&n<100){const t=new Date(Date.UTC(n,0,1));return t.setUTCFullYear(n),t.getTime()}return Date.UTC(n,0,1)}return 3===e?Date.UTC(n,i.getUTCMonth()+1,1):1===e?Date.UTC(n,i.getUTCMonth(),i.getUTCDate()+1):0===e?Date.UTC(n,i.getUTCMonth(),i.getUTCDate(),i.getUTCHours()+1):t}function v(t){return Math.pow(2,-1*t)}function g(t,e,i){return t/v(e)/i}function w(t){const e=new Date(t);return`${e.getFullYear()}-${e.getMonth()+1}-${e.getDate()}`}var b;!function(t){t[t.Backward=-1]="Backward",t[t.Stop=0]="Stop",t[t.Forward=1]="Forward"}(b||(b={}));var C=new class{constructor(){this.goToDuration=300,this.zoomToDuration=300,this.interval=1e-5,this.multipliers=[.25,.5,1,2,4,8,16],this.multiplier=1,this.direction=b.Stop,this.elapsedTimeTotal=0,this.models=[],this.views=[],this.animate=(t=>{const e=null==this.prevTimestamp?0:t-this.prevTimestamp;if(e>0||null==this.prevTimestamp){if(null==this.centerMarker&&null==this.zoomMarker)S.center=S.center+this.interval*this.multiplier*this.direction;else if(null!=this.centerMarker){const t=this.goToDuration-this.elapsedTimeTotal,i=Math.abs(this.centerMarker-S.center)/(t/e);t<e?(S.center=this.centerMarker,this.stop()):S.center=S.center+i*this.direction}else if(null!=this.zoomMarker){const t=this.zoomToDuration-this.elapsedTimeTotal,i=(this.zoomMarker-S.eventsBand.zoomLevel)/(t/e);t<e?(S.eventsBand.zoomLevel=this.zoomMarker,document.dispatchEvent(new CustomEvent(r)),this.stop()):S.eventsBand.zoomLevel=S.eventsBand.zoomLevel+i,S.minimapBands.forEach(t=>{S.eventsBand.zoomLevel<t.config.zoomLevel?t.zoomLevel=S.eventsBand.zoomLevel:t.zoomLevel!==t.config.zoomLevel&&(t.zoomLevel=t.config.zoomLevel)})}this.models.forEach(t=>t.update()),this.views.forEach(t=>t.update())}this.elapsedTimeTotal+=e,(this.isPlaying()||null!=this.zoomMarker)&&(S.center>0&&S.center<1||null!=this.centerMarker?(this.prevTimestamp=t,requestAnimationFrame(this.animate)):this.stop())})}registerModel(t){this.models.push(t)}registerView(t){this.views.push(t)}accelerate(){const t=this.multipliers.indexOf(this.multiplier);return t===this.multipliers.length-1?this.multipliers[this.multipliers.length-1]:(this.multiplier=this.multipliers[t+1],this.multiplier)}decelerate(){const t=this.multipliers.indexOf(this.multiplier);return 0===t?this.multipliers[0]:(this.multiplier=this.multipliers[t-1],this.multiplier)}goTo(t){this.centerMarker=t,t>S.center?this.playForward():this.playBackward()}zoomTo(t){null==this.zoomMarker&&(t<0&&(t=0),this.zoomMarker=t,this.play())}speed(t){const e=parseFloat(t);-1!==this.multipliers.indexOf(e)&&(this.multiplier=e)}isPlaying(){return this.direction!==b.Stop}isPlayingForward(){return this.direction===b.Forward}isPlayingBackward(){return this.direction===b.Backward}play(){requestAnimationFrame(this.animate)}playForward(){this.direction=b.Forward,this.play()}playBackward(){this.direction=b.Backward,this.play()}stop(){this.direction=b.Stop,this.centerMarker=null,this.zoomMarker=null,this.prevTimestamp=null,this.elapsedTimeTotal=0}toggle(){this.isPlaying()?this.stop():this.play()}};class x{constructor(t){this.defaultZoomLevel=0,this.zoomLevel=t.zoomLevel,this.height=Math.round(t.domains.reduce((t,e)=>t+e.heightRatio,0)*S.viewportHeight),this.top=Math.round(t.domains.reduce((t,e)=>Math.min(t,e.topOffsetRatio),1)*S.viewportHeight),C.registerModel(this)}get left(){return this._left}set left(t){t<-this.width+S.viewportWidth?t=S.viewportWidth-this.width:t>0&&(t=0),this._left=t}get zoomLevel(){return this._zoomLevel}set zoomLevel(t){t<0&&(t=0),this.visibleRatio=v(t),this.width=Math.round(S.viewportWidth/this.visibleRatio),this.time=this.visibleRatio*S.time,this.update(),this.granularity=h(S.from,S.to,this.visibleRatio),this.nextDate=function(t){if(t>=4){const e=l(t);return t=>{let i=new Date(t);const n=i.getFullYear()+e;return n>-1&&n<100?((i=new Date(i)).setUTCFullYear(n),i.getTime()):Date.UTC(n,0,1)}}return 3===t?t=>{const e=new Date(t);return Date.UTC(e.getFullYear(),e.getMonth()+1,1)}:2===t?t=>{const e=new Date(t);return Date.UTC(e.getFullYear(),e.getMonth(),e.getDate()+7)}:1===t?t=>{const e=new Date(t);return Date.UTC(e.getFullYear(),e.getMonth(),e.getDate()+1)}:0===t?t=>{const e=new Date(t);return Date.UTC(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours()+1)}:void 0}(this.granularity),this.pixelsPerMillisecond=this.width/S.time,this._zoomLevel=t}update(){const t=S.center*(S.time-this.time);this.from=S.from+t,this.to=this.from+this.time,this.left=Math.round(S.center*(S.viewportWidth-this.width))}positionAtTimestamp(t){return Math.round((t-S.from)*this.pixelsPerMillisecond)}proportionAtPosition(t){return(Math.abs(this.left)+t)/this.width}timestampAtProportion(t){return S.from+S.time*t}}class T extends x{constructor(t){super(t),this.config=t,this.domains=t.domains}}class M extends x{constructor(t){super(t),this.domains=t.domains,this.updateEvents()}updateEvents(){if(this.domains)for(const t of this.domains){const e=t.topOffsetRatio*S.viewportHeight,i=t.heightRatio*S.viewportHeight-s;for(const s of t.orderedEvents.events)s.left=this.positionAtTimestamp(s.from)+this.left,s.width=Math.round(s.time*this.pixelsPerMillisecond),s.padding=Math.round(s.space*this.pixelsPerMillisecond),s.width<1&&(s.width=1),s.top=e+i-(s.row+1)*(n+2)}}update(){super.update(),this.updateEvents()}getEventByCoordinates(t,e){const i=this.timestampAtProportion(this.proportionAtPosition(t)),o=this.domains.find(t=>{const i=S.viewportOffset+t.topOffsetRatio*S.viewportHeight,n=S.viewportOffset+t.heightRatio*S.viewportHeight;return i<e&&i+n>e});return o.orderedEvents.events.find(t=>{if(!(t.from<i&&t.from+t.time+t.space>i))return!1;const r=S.viewportOffset+(o.topOffsetRatio+o.heightRatio)*S.viewportHeight-s,a=Math.floor((r-e)/(n+2));return t.row===a})}zoomIn(){C.zoomTo(this.zoomLevel+1)}zoomOut(){C.zoomTo(this.zoomLevel-1)}}class y{constructor(){this.heightRatio=1,this.rulers=!0,this.rulerLabels=!0,this.topOffsetRatio=0}}class E extends y{constructor(){super(...arguments),this.targets=[]}}class z extends y{}class B{constructor(){this.domains=[],this.zoomLevel=0}}class D{constructor(){this.center=.5,this.minimaps=[]}}class L{constructor(){this.events=[],this.row_count=0}}const O=8;function _(t,e){if(!t.length)return new L;let i=0;const s=[],o=2*n/e;return{events:t=t.map(t=>{let n;null==t.label&&(t.label="NO LABEL"),t.from=t.date_min||t.date,t.to=t.end_date_max||t.end_date,t.time=null==t.to?0:t.to-t.from,t.space=0,t.time||(null==t.label&&(t.label="NO LABEL"),t.space=t.label.length*O/e+o);let r=0;for(;null==n&&r<s.length;){let e=0,i=!0;for(;i&&e<s[r].length&&!(t.to<s[r][e][0]);)i=t.from>s[r][e][1],e++;i&&(s[r].push([t.from,t.from+t.time+t.space]),n=r),r++}return null==n&&(n=s.push([[t.from,t.from+t.time+t.space]])-1),n>i&&(i=n),t.row=n,t}),row_count:s.length}}var U=function(t,e,i,n){return new(i||(i=Promise))(function(s,o){function r(t){try{h(n.next(t))}catch(t){o(t)}}function a(t){try{h(n.throw(t))}catch(t){o(t)}}function h(t){t.done?s(t.value):new i(function(e){e(t.value)}).then(r,a)}h((n=n.apply(t,e||[])).next())})};function k(t,e){return U(this,void 0,void 0,function*(){return null==t.events?(console.error("[DomainConfig] No events band in config!"),t):null!=t.events.domains&&t.events.domains.length?(t.events.domains=t.events.domains.map(t=>(null==t.events&&null==t.orderedEvents?console.error("[DomainConfig] No events in config!"):null==t.orderedEvents&&(t.orderedEvents=function(t,e,i){if("object"==typeof WebAssembly&&"function"==typeof WebAssembly.instantiate&&i){console.warn("[Timeline] Using WebAssembly");const n=JSON.stringify(t),s=i.order_events(n,e);return JSON.parse(s)}return _(t,e)}(t.events,e),delete t.events),Object.assign({},new z,t))),(t=Object.assign({},new D,t)).events.domains=t.events.domains.map(t=>Object.assign({},new z,t)),t.events=Object.assign({},new B,t.events),t.minimaps=t.minimaps.map(t=>((t=Object.assign({},new B,t)).domains.length||t.domains.push({}),t.domains=t.domains.map(t=>Object.assign({},new E,t)),Object.assign({},new B,t))),t):(console.error("[DomainConfig] No events band domains in config!"),t)})}var P=function(t,e,i,n){return new(i||(i=Promise))(function(s,o){function r(t){try{h(n.next(t))}catch(t){o(t)}}function a(t){try{h(n.throw(t))}catch(t){o(t)}}function h(t){t.done?s(t.value):new i(function(e){e(t.value)}).then(r,a)}h((n=n.apply(t,e||[])).next())})};var S=new class{constructor(){this.defaultCenter=.5,this._center=this.defaultCenter,this.centerChangeDone=p(()=>{document.dispatchEvent(new CustomEvent(o))},300)}init(t){return P(this,void 0,void 0,function*(){null==t.rootElement&&console.error("[init] No rootElement found"),this.dimensions=t.rootElement;const e=[],i=[];for(const n of t.events.domains){let t;n.hasOwnProperty("events")&&(n.events.sort(d),t=n.events),null==t&&(t=n.orderedEvents.events),e.push(t[0].date_min||t[0].date),i.push(t.reduce((t,e)=>Math.max(t,e.end_date||-1/0,e.end_date_max||-1/0),-1/0))}this.from=Math.min(...e),this.to=Math.max(...i),this.time=this.to-this.from;const n=g(this.viewportWidth,t.events.zoomLevel||0,this.to-this.from);null!=(t=yield k(t,n)).center&&(this.center=t.center),this.minimapBands=t.minimaps.map(t=>new T(t)),this.eventsBand=new M(t.events)})}get center(){return this._center}set center(t){0===this._center&&t<0||1===this._center&&t>1||(this._center=t<0?0:t>1?1:t,this.centerChangeDone())}set dimensions(t){const e=getComputedStyle(t);this.viewportHeight=parseInt(e.getPropertyValue("height"),10),this.viewportOffset=t.getBoundingClientRect().top,this.viewportWidth=parseInt(e.getPropertyValue("width"),10)}};let R;if("undefined"!=typeof window){const t=document.createElement("style");document.head.appendChild(t),R=t.sheet}const A={};var F=(t,e,i,n)=>{if(!e)return document.createElement(t);let s;return A.hasOwnProperty(e)?s=A[e].cloneNode(!1):((s=document.createElement(t)).classList.add(e),i&&R.insertRule(`.${e} { ${i.join(";").concat(";")} }`),A[e]=s.cloneNode(!1)),n&&s.setAttribute("style",n.join(";").concat(";")),s};var W=new class{constructor(){this.eventsListeners=[]}register(t,e,i=document){i.addEventListener(t,e),this.eventsListeners.push([t,e,i])}flush(){this.eventsListeners.forEach(t=>{const[e,i,n]=t;n.removeEventListener(e,i)}),this.eventsListeners=[]}};class ${constructor(t){this.band=t,this.onMouseDown=(t=>{document.addEventListener("mouseup",this.onMouseUp),this.dragOffset=t.clientX,this.dragStart=this.band.left}),this.onMouseMove=(t=>{if(this.dragOffset&&this.band.zoomLevel>0){const e=this.dragStart-(this.dragOffset-t.clientX);S.center=e/(S.viewportWidth-this.band.width),C.play()}}),this.onMouseUp=(t=>{this.dragOffset=null,document.removeEventListener("mouseup",this.onMouseUp)}),this.onDblClick=(t=>{const e=this.band.proportionAtPosition(t.clientX);C.goTo(e)})}render(){return this.rootElement=F("div","band-wrap",["position: absolute","z-index: 1"],[`height: ${this.band.height}px`,`top: ${this.band.top}px`,`width: ${S.viewportWidth}px`]),this.band.zoomLevel>0&&(W.register("mousedown",this.onMouseDown,this.rootElement),W.register("mousemove",this.onMouseMove,this.rootElement)),W.register("dblclick",this.onDblClick,this.rootElement),this.rootElement}resize(){this.rootElement.style.cssText=`height: ${this.band.height}px; top: ${this.band.top}px; width: ${S.viewportWidth}px;`}}class H{constructor(t,e){this.onChange=e,this.animator=C,this.handleChange=(()=>{const{from:t,to:e}=S.eventsBand;this.onChange({center:S.center,visibleFrom:t,visibleTo:e,zoomLevel:S.eventsBand.zoomLevel})}),document.addEventListener("keydown",t=>{189===t.keyCode&&S.eventsBand.zoomOut(),187===t.keyCode&&S.eventsBand.zoomIn()}),t.addEventListener("wheel",t=>{0===Math.abs(t.deltaX)&&0!==t.deltaY&&(t.deltaY<0&&S.eventsBand.zoomOut(),t.deltaY>0&&S.eventsBand.zoomIn())}),null!=this.onChange&&"function"==typeof this.onChange&&(document.addEventListener(o,this.handleChange),document.addEventListener(r,this.handleChange))}zoomIn(){S.eventsBand.zoomIn()}zoomOut(){S.eventsBand.zoomOut(),this.handleChange()}}class j extends ${constructor(t,e){super(t),this.band=t,this.select=e,this.onClick=(t=>{const e=this.band.getEventByCoordinates(t.clientX,t.clientY);e&&this.select&&(this.select(e),function(t,...e){console.log(t.label,t,t.left,w(t.from),w(t.to),e)}(e))})}render(){const t=super.render();return W.register("click",this.onClick,this.rootElement),t}}class Y{constructor(){this.font="10px sans-serif",this.offsiteCanvas=F("canvas"),this.clear=(()=>{this.ctx.clearRect(S.eventsBand.top,0,this.canvas.width,S.eventsBand.height),S.minimapBands.filter(t=>0!==t.zoomLevel).forEach(t=>this.ctx.clearRect(0,t.top,this.canvas.width,t.height))}),this.update=(()=>{this.canvas.width===S.viewportWidth&&this.canvas.height===S.viewportHeight||(this.canvas.width=S.viewportWidth,this.canvas.height=S.viewportHeight,this.indicatorsCanvas.width=S.viewportWidth,this.indicatorsCanvas.height=S.viewportHeight,this.drawStaticMinimapBands()),this.clear(),this.drawRulers(S.eventsBand),this.drawEvents(),this.drawEventsText(),S.minimapBands.filter(t=>0!==t.zoomLevel).forEach(t=>{t.domains.forEach(e=>{this.drawMinimap(t,e)}),this.drawRulers(t)}),this.drawIndicators()}),C.registerView(this),this.offsiteCtx=this.offsiteCanvas.getContext("2d")}render(){return this.canvas=F("canvas","minimap",["position: absolute"]),this.canvas.width=S.viewportWidth,this.canvas.height=S.viewportHeight,this.ctx=this.canvas.getContext("2d"),this.ctx.font=this.font,this.indicatorsCanvas=F("canvas","minimap",["position: absolute"],["z-index: 1"]),this.indicatorsCanvas.width=S.viewportWidth,this.indicatorsCanvas.height=S.viewportHeight,this.indicatorsCtx=this.indicatorsCanvas.getContext("2d"),this.update(),this.drawStaticMinimapBands(),[this.canvas,this.indicatorsCanvas]}drawStaticMinimapBands(){S.minimapBands.filter(t=>0===t.zoomLevel).forEach(t=>{t.domains.forEach(e=>{this.drawMinimap(t,e)}),this.drawRulers(t)})}drawEvents(){this.ctx.beginPath();for(const t of S.eventsBand.domains)for(const e of t.orderedEvents.events)e.from>S.eventsBand.to||e.to<S.eventsBand.from||(e.time?this.ctx.rect(e.left,e.top,e.width,n):(this.ctx.moveTo(e.left,e.top+n/2),this.ctx.arc(e.left,e.top+n/2,n/3,0,2*Math.PI)));this.ctx.fillStyle="rgba(126, 0, 0, .3)",this.ctx.fill()}drawEventsText(){this.ctx.fillStyle="rgb(126, 0, 0)";for(const t of S.eventsBand.domains)for(const e of t.orderedEvents.events){if(e.from>S.eventsBand.to||e.to<S.eventsBand.from)continue;let t=0===e.time?e.padding:e.width,i=e.left;if(e.left<0&&0!==e.time&&(t=e.width+e.left,i=0),e.label.length*a<=t){const t=e.time?3:8;this.ctx.fillText(e.label,i+t,e.top+n-3)}}}drawMinimap(t,e){const i=t.height-s,n=t.domains.reduce((t,e)=>{const i=e.targets.map(t=>S.eventsBand.domains[t].orderedEvents.row_count);return Math.max(t,...i)},0);let o=i/n;function r(i,n,s=t.top){i.beginPath();const r=t.positionAtTimestamp(t.from);e.targets.forEach(e=>{const a=S.eventsBand.domains[e];for(const e of a.orderedEvents.events){if(e.from>t.to||e.to<t.from)continue;const a=Math.round(e.time*t.pixelsPerMillisecond),h=t.positionAtTimestamp(null!=e.date_min?e.date_min:e.date),l=s+n-(e.row+1)*o,d=a<1?1:a;i.rect(h-r,l,d,o)}}),i.fillStyle="rgba(0, 0, 0, .2)",i.fill()}o<1?(o=1,this.offsiteCanvas.width=S.viewportWidth,this.offsiteCanvas.height=n,r(this.offsiteCtx,n,0),this.ctx.drawImage(this.offsiteCanvas,0,t.top,S.viewportWidth,i)):(o=Math.round(o),r(this.ctx,i))}drawIndicators(){this.indicatorsCtx.clearRect(0,0,S.viewportWidth,S.viewportHeight),this.indicatorsCtx.beginPath(),S.minimapBands.forEach(t=>{t.domains.forEach(e=>{const i=Math.round(e.topOffsetRatio*S.viewportHeight),n=t.positionAtTimestamp(S.eventsBand.from)+t.left;this.indicatorsCtx.rect(0,i,n,t.height);const o=t.positionAtTimestamp(S.eventsBand.to)+t.left;this.indicatorsCtx.rect(o,i,S.viewportWidth,t.height),this.indicatorsCtx.rect(n,i+t.height-s,o-n,s)})}),this.indicatorsCtx.fillStyle="rgba(0, 0, 0, .1)",this.indicatorsCtx.fill(),this.indicatorsCtx.fillStyle="rgba(255, 0, 0, .5)";const t=S.eventsBand.positionAtTimestamp(S.eventsBand.timestampAtProportion(S.center))+S.eventsBand.left;this.indicatorsCtx.fillRect(t-1,0,2,S.viewportHeight),this.indicatorsCtx.closePath()}drawRulers(t){this.ctx.beginPath(),this.ctx.fillStyle="rgb(150, 150, 150)";for(const e of t.domains){if(!e.rulers)continue;let i=f(t.from,t.granularity);const n=e.topOffsetRatio*S.viewportHeight,s=e.heightRatio*S.viewportHeight;for(;i<t.to;){const o=t.positionAtTimestamp(i)+t.left;this.ctx.moveTo(o,n),this.ctx.lineTo(o,n+s),e.rulerLabels&&this.ctx.fillText(m(i,t.granularity),o+3,n+s-3),i=t.nextDate(i)}}this.ctx.strokeStyle="rgb(200, 200, 200)",this.ctx.stroke()}}class N{constructor(t){this.domain=t}render(){const t=F("div","events-label-wrapper",["border-top: 1px solid #CCC","position: absolute","width: 100%"],[`top: ${100*this.domain.topOffsetRatio}%`]),e=F("div","events-label",["background: white","border-bottom-right-radius: 4px","box-shadow: 1px 2px 4px #AAA","display: inline-block","color: #444","font-size: .8em","font-family: sans-serif","padding: 4px 8px"]);return e.innerText=this.domain.label,t.appendChild(e),t}}i.d(e,"default",function(){return I}),i.d(e,"TimelineConfig",function(){return D}),i.d(e,"orderEvents",function(){return _}),i.d(e,"OrderedEvents",function(){return L}),i.d(e,"calcPixelsPerMillisecond",function(){return g});class I extends H{constructor(t,e,i){super(t.rootElement,e),this.config=t,this.onSelect=i,this.appendToWrapper=(t=>{let e=t.render();Array.isArray(e)||(e=[e]),e.forEach(t=>this.wrapper.appendChild(t))}),this.reload=(t=>{null!=t&&S.init(t),this.resize()}),this.resize=(()=>{S.dimensions=this.config.rootElement,S.eventsBand.zoomLevel=S.eventsBand.zoomLevel,this.eventsBandView.resize(),S.minimapBands.forEach(t=>t.zoomLevel=t.zoomLevel),this.minimapBandViews.forEach(t=>t.resize()),this.animator.play()}),S.init(t).then(()=>{t.rootElement.appendChild(this.render());const e=p(this.resize,600);window.addEventListener("resize",e)})}render(){return this.wrapper=F("div","wrapper",["box-sizing: border-box","height: 100%","overflow: hidden","position: relative","user-select: none","width: 100%"]),this.appendToWrapper(new Y),this.eventsBandView=new j(S.eventsBand,this.onSelect),this.appendToWrapper(this.eventsBandView),this.minimapBandViews=S.minimapBands.map(t=>new $(t)),this.minimapBandViews.forEach(this.appendToWrapper),this.renderLabels(),this.wrapper}renderLabels(){S.eventsBand.domains.filter(t=>null!=t.label).map(t=>new N(t)).forEach(this.appendToWrapper)}}}])});
import { Ratio } from "./constants";
import Band from "./models/band";
import Canvas from "./views/canvas";
export declare type Multiplier = .25 | .5 | 1 | 2 | 4 | 8 | 16;

@@ -13,7 +15,7 @@ export declare class Animator {

private elapsedTimeTotal;
private modelUpdaters;
private viewUpdaters;
private models;
private views;
private zoomMarker;
registerModelUpdaters(update: any): void;
registerViewUpdaters(update: any): void;
registerModel(model: Band): void;
registerView(view: Canvas): void;
animate: (timestamp: any) => void;

@@ -20,0 +22,0 @@ accelerate(): number;

@@ -7,2 +7,3 @@ import { Animator } from './animator';

visibleTo: Milliseconds;
zoomLevel: number;
}

@@ -13,7 +14,3 @@ export declare type OnChangeFunction = (props: OnChangeFunctionProps, e?: Event) => void;

animator: Animator;
constructor(rootElement: HTMLElement, onChange: (changeProps: {
center: Ratio;
visibleFrom: Milliseconds;
visibleTo: Milliseconds;
}) => void);
constructor(rootElement: HTMLElement, onChange: (changeProps: OnChangeFunctionProps) => void);
private handleChange;

@@ -20,0 +17,0 @@ zoomIn(): void;

import { RawEv3nt } from "./models/event";
export declare const EVENT_MIN_SPACE = 160;
export declare const EVENT_HEIGHT = 14;

@@ -8,2 +7,4 @@ export declare const EVENT_ROW_HEIGHT = 20;

export declare const CENTER_CHANGE_DONE = "CENTER_CHANGE_DONE";
export declare const ZOOM_DONE = "ZOOM_DONE";
export declare const PIXELS_PER_LETTER = 8;
export declare type Milliseconds = number;

@@ -10,0 +11,0 @@ export declare type Grid = [Milliseconds, Milliseconds][][];

import Config from './models/config/index';
import { calcPixelsPerMillisecond } from './utils';
import { orderEvents, OrderedEvents } from './utils/events.worker';
import { OrderedEvents, orderEvents } from './utils/events.worker';
import Api from './api';

@@ -8,3 +8,3 @@ export { Config as TimelineConfig, orderEvents, OrderedEvents, calcPixelsPerMillisecond };

protected config: Config;
private onSelect;
private onSelect?;
private minimapBandViews;

@@ -14,4 +14,4 @@ private eventsBandView;

constructor(config: Config, onChange?: any, onSelect?: any);
private render();
private renderLabels();
private render;
private renderLabels;
private appendToWrapper;

@@ -18,0 +18,0 @@ reload: (config?: Config) => void;

@@ -8,2 +8,4 @@ import Band from '.';

constructor(config: BandConfig<EventsDomainConfig>);
private updateEvents;
update(): void;
getEventByCoordinates(x: Pixels, y: Pixels): RawEv3nt;

@@ -10,0 +12,0 @@ zoomIn(): void;

@@ -21,3 +21,3 @@ import { Granularity } from '../../utils/dates';

constructor(config: BandConfig<MinimapDomainConfig | EventsDomainConfig>);
update: () => void;
update(): void;
positionAtTimestamp(date: Milliseconds): Pixels;

@@ -24,0 +24,0 @@ proportionAtPosition(position: Pixels): Ratio;

@@ -22,2 +22,3 @@ import { Milliseconds, Pixels } from '../constants';

left: Pixels;
padding: Pixels;
top: Pixels;

@@ -24,0 +25,0 @@ width: Pixels;

@@ -15,3 +15,3 @@ import { Ratio, Milliseconds, Pixels } from "../constants";

viewportWidth: Pixels;
init(config: Config): void;
init(config: Config): Promise<void>;
private _center;

@@ -18,0 +18,0 @@ center: Ratio;

@@ -14,6 +14,5 @@ import { Milliseconds } from "../constants";

CENTURY_5 = 9,
MILLENIUM = 10,
MILLENIUM = 10
}
export declare const isEqual: (date1: Date, date2: Date) => boolean;
export declare const format: (date: Date, granularity: Granularity) => string;
export declare const getGranularity: (from: number, to: number, visibleRatio: number) => Granularity;

@@ -20,0 +19,0 @@ export declare const getStep: (granularity: Granularity) => number;

@@ -1,16 +0,7 @@

import { Milliseconds, Grid } from "../constants";
import { Milliseconds } from "../constants";
import { RawEv3nt } from "../models/event";
export declare class OrderedEvents {
events: RawEv3nt[];
grid: Grid;
rowCount: number;
row_count: number;
}
export declare function orderEvents(events: RawEv3nt[], pixelsPerMillisecond: Milliseconds): OrderedEvents;
export declare function eventsWorker(e: {
data: {
events: RawEv3nt[];
orderEventsURL: string;
};
}): void;
declare const _default: (events: RawEv3nt[], done: (response: OrderedEvents) => void) => void;
export default _default;

@@ -11,1 +11,2 @@ import { RawEv3nt } from "../models/event";

export declare function calcPixelsPerMillisecond(viewportWidth: Pixels, zoomLevel: number, totalTime: Milliseconds): number;
export declare function logEvent(event: RawEv3nt, ...rest: any[]): void;
import Config from "../models/config";
import { Pixels } from "../constants";
export default function prepareConfig(config: Config, pixelsPerMillisecond: Pixels): Config;
export default function prepareConfig(config: Config, pixelsPerMillisecond: Pixels): Promise<Config>;

@@ -12,10 +12,10 @@ import View from '../index';

render(): HTMLCanvasElement[];
private drawStaticMinimapBands();
private drawStaticMinimapBands;
private clear;
update: () => void;
private drawEvents();
private drawEventsText();
private drawMinimap(band, domain);
private drawIndicators();
private drawRulers(band);
private drawEvents;
private drawEventsText;
private drawMinimap;
private drawIndicators;
private drawRulers;
}
{
"name": "timeline",
"version": "3.0.1",
"version": "3.0.2",
"description": "",

@@ -10,19 +10,31 @@ "main": "build/bundle.js",

"scripts": {
"prebuild": "rm -rf build",
"clean": "rm -rf build",
"build": "webpack --mode production",
"build:dev": "webpack --mode development",
"test": "jest",
"prewatch": "rm -rf build",
"server:dev": "browser-sync start -s --no-open -f \"build\" \"index.html\"",
"watch": "webpack -w --mode development"
"start": "webpack-dev-server --mode production",
"start:dev": "webpack-dev-server --mode development",
"watch": "webpack -w --mode development",
"prebuild": "npm run clean",
"prebuild:dev": "npm run clean",
"prestart": "npm run clean",
"prestart:dev": "npm run clean",
"prewatch": "npm run clean"
},
"devDependencies": {
"@types/jest": "^22.2.2",
"browser-sync": "^2.24.5",
"jest": "^22.4.3",
"pg": "^7.4.1",
"ts-jest": "^22.4.2",
"ts-loader": "^4.1.0",
"typescript": "^2.8.1",
"webpack": "^4.4.1",
"webpack-cli": "^2.0.13"
"@types/jest": "^23.3.1",
"browser-sync": "^2.24.6",
"jest": "^23.4.2",
"pg": "^7.4.3",
"ts-jest": "^23.1.2",
"ts-loader": "^4.4.2",
"typescript": "^3.0.1",
"webpack": "^4.16.4",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.5"
},

@@ -29,0 +41,0 @@ "jest": {

# Timeline
## Development
- `npm run watch` starts a Webpack watch to build the /src
- start any webserver from the project root (for example: `python -m http.server`) and open the test page at `http://localhost:{PORT}`
## Development server
- `npm run start` starts a Webpack dev server in production mode
- `npm run start:dev` starts a Webpack dev server in development mode
import props from "./models/props";
import { Milliseconds, Ratio } from "./constants";
import { Milliseconds, Ratio, ZOOM_DONE } from "./constants";
import Band from "./models/band";
import Canvas from "./views/canvas";

@@ -35,12 +37,13 @@ export type Multiplier = .25 | .5 | 1 | 2 | 4 | 8 | 16

private modelUpdaters: any[] = []
private viewUpdaters: any[] = []
private models: Band[] = []
private views: Canvas[] = []
private zoomMarker: Ratio
registerModelUpdaters(update) {
this.modelUpdaters.push(update)
registerModel(model: Band) {
this.models.push(model)
}
registerViewUpdaters(update) {
this.viewUpdaters.push(update)
registerView(view: Canvas) {
this.views.push(view)
}

@@ -73,2 +76,3 @@

props.eventsBand.zoomLevel = this.zoomMarker
document.dispatchEvent(new CustomEvent(ZOOM_DONE))
this.stop()

@@ -95,6 +99,6 @@ }

// Update the models. This is real quick ~0ms
this.modelUpdaters.forEach(update => update())
this.models.forEach(model => model.update())
// Update the view. This is too slow ~30-50ms
this.viewUpdaters.forEach(update => update())
this.views.forEach(view => view.update())
}

@@ -135,2 +139,3 @@

zoomTo(nextZoomLevel: Ratio) {
if (this.zoomMarker != null) return
if (nextZoomLevel < 0) nextZoomLevel = 0

@@ -137,0 +142,0 @@ this.zoomMarker = nextZoomLevel

import animator, { Animator } from './animator'
import { CENTER_CHANGE_DONE, Ratio, Milliseconds } from './constants'
import { CENTER_CHANGE_DONE, Ratio, Milliseconds, ZOOM_DONE } from './constants'
import props from './models/props';
export interface OnChangeFunctionProps { center: Ratio, visibleFrom: Milliseconds, visibleTo: Milliseconds }
export interface OnChangeFunctionProps { center: Ratio, visibleFrom: Milliseconds, visibleTo: Milliseconds, zoomLevel: number }
export type OnChangeFunction = (props: OnChangeFunctionProps, e?: Event) => void

@@ -13,3 +13,3 @@

rootElement: HTMLElement,
private onChange: (changeProps: { center: Ratio, visibleFrom: Milliseconds, visibleTo: Milliseconds }) => void
private onChange: (changeProps: OnChangeFunctionProps) => void
) {

@@ -30,2 +30,3 @@ document.addEventListener('keydown', (ev) => {

document.addEventListener(CENTER_CHANGE_DONE, this.handleChange)
document.addEventListener(ZOOM_DONE, this.handleChange)
}

@@ -41,2 +42,3 @@ }

visibleTo: to,
zoomLevel: props.eventsBand.zoomLevel
})

@@ -43,0 +45,0 @@ }

import { RawEv3nt } from "./models/event";
// The minimal space (in px) an event should take. This space can be bigger
// than the width of the event, to accommodate the label.
export const EVENT_MIN_SPACE = 160
export const EVENT_HEIGHT = 14

@@ -16,3 +12,6 @@

export const CENTER_CHANGE_DONE = 'CENTER_CHANGE_DONE'
export const ZOOM_DONE = 'ZOOM_DONE'
export const PIXELS_PER_LETTER = 8
export type Milliseconds = number

@@ -19,0 +18,0 @@ export type Grid = [Milliseconds, Milliseconds][][]

@@ -6,7 +6,7 @@ import props from './models/props'

import { debounce, calcPixelsPerMillisecond } from './utils'
import { orderEvents, OrderedEvents } from './utils/events.worker'
import { OrderedEvents, orderEvents } from './utils/events.worker'
import Api from './api'
import EventsBandView from './views/band/events'
import Canvas from './views/canvas'
import View from './views';
import View from './views'
import Label from './views/label'

@@ -16,3 +16,6 @@

// TODO add a roadmap
// TODO add config to add space/time before first and last events
// TODO use available vertical space (not fixed to EVENT_HEIGHT), see examples/100m
// TODO zoom in to milliseconds
// TODO add API to constrain by spacial data
// TODO Add open ranges (ie: people still alive)

@@ -24,3 +27,2 @@ // TODO If event granularity is equal to band granularity a point in time should be rendered as an interval (as unsure?)

// TODO make indicator draggable
// TODO add config to add space/time before first and last events
// TODO show when playing animation (button pressed?)

@@ -35,8 +37,8 @@ export default class Timeline extends Api {

props.init(config)
props.init(config).then(() => {
config.rootElement.appendChild(this.render())
config.rootElement.appendChild(this.render())
const debouncedResize = debounce(this.resize, 600)
window.addEventListener('resize', debouncedResize)
const debouncedResize = debounce(this.resize, 600)
window.addEventListener('resize', debouncedResize)
})
}

@@ -73,3 +75,2 @@

// TODO use a class (like BandView) and a render method and appendToWrapper
private renderLabels() {

@@ -80,3 +81,2 @@ props.eventsBand.domains

.forEach(this.appendToWrapper)
}

@@ -83,0 +83,0 @@

@@ -14,4 +14,27 @@ import Band from '.'

this.domains = config.domains
this.updateEvents()
}
private updateEvents() {
if (!this.domains) return
for (const domain of this.domains) {
const offsetY = domain.topOffsetRatio * props.viewportHeight
const domainHeight = (domain.heightRatio * props.viewportHeight) - DATE_BAR_HEIGHT
for (const event of domain.orderedEvents.events) {
event.left = this.positionAtTimestamp(event.from) + this.left
event.width = Math.round((event.time) * this.pixelsPerMillisecond)
event.padding = Math.round((event.space) * this.pixelsPerMillisecond)
if (event.width < 1) event.width = 1
event.top = offsetY + domainHeight - ((event.row + 1) * (EVENT_HEIGHT + 2))
}
}
}
update() {
super.update()
this.updateEvents()
}
getEventByCoordinates(x: Pixels, y: Pixels): RawEv3nt {

@@ -18,0 +41,0 @@ const timestamp = this.timestampAtProportion(this.proportionAtPosition(x))

@@ -71,6 +71,6 @@ import { getGranularity, Granularity, subsequentDate } from '../../utils/dates'

this.top = Math.round(config.domains.reduce((prev, curr) => Math.min(prev, curr.topOffsetRatio), 1) * props.viewportHeight)
animator.registerModelUpdaters(this.update)
animator.registerModel(this)
}
update = () => {
update() {
const offset = props.center * (props.time - this.time)

@@ -77,0 +77,0 @@ this.from = props.from + offset

@@ -42,3 +42,2 @@ import { Ratio } from "../../constants"

export default class Config {

@@ -45,0 +44,0 @@ center?: Ratio = .5

@@ -30,6 +30,7 @@ import { Milliseconds, Pixels } from '../constants';

// Point in Time = label width + padding
// Interval = time + padding
// Interval = padding
space: Milliseconds
left: Pixels
padding: Pixels
top: Pixels

@@ -36,0 +37,0 @@ width: Pixels

@@ -28,3 +28,3 @@ import { CENTER_CHANGE_DONE, Ratio, Milliseconds, Pixels } from "../constants"

init(config: Config) {
async init(config: Config) {
if (config.rootElement == null) console.error('[init] No rootElement found')

@@ -52,7 +52,14 @@

this.time = this.to - this.from
// const pixelsPerMillisecond2 = calcPixelsPerMillisecond(this.viewportWidth, config.events.zoomLevel || 0, this.to - this.from)
// this.from -= (this.viewportWidth / 8) / pixelsPerMillisecond2
// this.to += (this.viewportWidth / 8) / pixelsPerMillisecond2
// // this.to += this.time * .1
// this.time = this.to - this.from
const pixelsPerMillisecond = calcPixelsPerMillisecond(this.viewportWidth, config.events.zoomLevel || 0, this.to - this.from)
config = prepareConfig(config, pixelsPerMillisecond)
config = await prepareConfig(config, pixelsPerMillisecond)
this.time = this.to - this.from
if (config.center != null) this.center = config.center

@@ -59,0 +66,0 @@

@@ -20,25 +20,13 @@ import { Milliseconds, Ratio } from "../constants"

export const format = (date: Date, granularity: Granularity): string => {
if (date == null) return '∞';
// export const format = (date: Date, granularity: Granularity): string => {
// if (date == null) return '∞';
let displayDate = date.getFullYear().toString();
// let displayDate = date.getUTCFullYear().toString();
if (granularity >= Granularity.MONTH) {
const months = [
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',
];
displayDate = `${months[date.getMonth()]} ${displayDate}`;
}
if (granularity >= Granularity.DAY) {
displayDate = `${date.getDate()} ${displayDate}`;
}
if (granularity === Granularity.HOUR) {
displayDate = `${date.getHours()}:${date.getMinutes()} ${displayDate}`;
}
// if (granularity >= Granularity.MONTH) displayDate = `${months[date.getMonth()]} ${displayDate}`
// if (granularity >= Granularity.DAY) displayDate = `${date.getUTCDate()} ${displayDate}`
// if (granularity === Granularity.HOUR) displayDate = `${date.getUTCHours()}:${date.getUTCMinutes()} ${displayDate}`
return displayDate;
}
// return displayDate;
// }

@@ -144,11 +132,18 @@ export const getGranularity = (from: Milliseconds, to: Milliseconds, visibleRatio: Ratio): Granularity => {

const date = new Date(d)
if (granularity >= Granularity.YEAR) {
return date.getUTCFullYear().toString()
} else if (granularity === Granularity.MONTH) {
}
if (granularity === Granularity.MONTH) {
let body = months[date.getUTCMonth()]
if (date.getUTCMonth() === 0) body = `${date.getUTCFullYear().toString()}, ${body}`
return body
} else if (granularity === Granularity.WEEK) {
}
if (granularity === Granularity.WEEK) {
return `${months[date.getUTCMonth()]}, week ${getWeekNumber(date)}`
} else if (granularity === Granularity.DAY) {
}
if (granularity === Granularity.DAY) {
let body = days[date.getUTCDay()]

@@ -158,5 +153,7 @@ body = `${body}, ${months[date.getUTCMonth()]} ${date.getUTCDate()}`

return body
} else if (granularity === Granularity.HOUR) {
}
if (granularity === Granularity.HOUR) {
return `${date.getUTCHours()}:00`
}
}

@@ -6,4 +6,4 @@ import { Milliseconds, Grid, EVENT_HEIGHT } from "../constants"

events: RawEv3nt[] = []
grid: Grid = []
rowCount: number = 0
// grid: Grid = []
row_count: number = 0
}

@@ -32,2 +32,4 @@

if (event.label == null) event.label = 'NO LABEL'
event.from = event.date_min || event.date

@@ -42,3 +44,3 @@ event.to = event.end_date_max || event.end_date

}
// Search the grid for a row which has space for the current event

@@ -89,25 +91,25 @@ let rowIterator = 0

// to,
grid,
rowCount
// grid,
row_count: grid.length
}
}
export function eventsWorker(e: { data: { events: RawEv3nt[], orderEventsURL: string } }) {
importScripts(e.data.orderEventsURL)
// export function eventsWorker(e: { data: { events: RawEv3nt[], orderEventsURL: string } }) {
// importScripts(e.data.orderEventsURL)
//@ts-ignore Typescript wants the second parameter (targetOrigin), but the browser will throw
postMessage(orderEvents(e.data.events))
}
// //@ts-ignore Typescript wants the second parameter (targetOrigin), but the browser will throw
// postMessage(orderEvents(e.data.events))
// }
export default (events: RawEv3nt[], done: (response: OrderedEvents) => void) => {
const orderEventsURL = URL.createObjectURL(new Blob([orderEvents]))
const func = `onmessage = ${eventsWorker.toString()}`
const objectURL = URL.createObjectURL(new Blob([func]))
let worker: Worker = new Worker(objectURL)
worker.postMessage({ events, orderEventsURL })
worker.onmessage = (e) => {
URL.revokeObjectURL(objectURL)
worker.terminate()
done(e.data)
}
}
// export default (events: RawEv3nt[], done: (response: OrderedEvents) => void) => {
// const orderEventsURL = URL.createObjectURL(new Blob([orderEvents]))
// const func = `onmessage = ${eventsWorker.toString()}`
// const objectURL = URL.createObjectURL(new Blob([func]))
// let worker: Worker = new Worker(objectURL)
// worker.postMessage({ events, orderEventsURL })
// worker.onmessage = (e) => {
// URL.revokeObjectURL(objectURL)
// worker.terminate()
// done(e.data)
// }
// }

@@ -94,2 +94,10 @@ import { RawEv3nt } from "../models/event";

return (viewportWidth / visibleRatio(zoomLevel)) / totalTime
}
function formatDate(ts) {
const d = new Date(ts)
return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`
}
export function logEvent(event: RawEv3nt, ...rest) {
console.log(event.label, event, event.left, formatDate(event.from), formatDate(event.to), rest)
}
import Config, { EventsDomainConfig, BandConfig, MinimapDomainConfig } from "../models/config"
import { orderEvents } from "./events.worker"
import { orderEvents, OrderedEvents } from "./events.worker"
import { Pixels } from "../constants"
import { RawEv3nt } from "../models/event";
export default function prepareConfig(config: Config, pixelsPerMillisecond: Pixels): Config {
function orderEventsProxy(events: RawEv3nt[], pixelsPerMillisecond: Pixels, orderEventsWasm?): OrderedEvents {
// @ts-ignore
if (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function" && orderEventsWasm) {
console.warn("[Timeline] Using WebAssembly")
const es = JSON.stringify(events)
const es2 = orderEventsWasm.order_events(es, pixelsPerMillisecond)
return JSON.parse(es2)
} else {
return orderEvents(events, pixelsPerMillisecond)
}
}
export default async function prepareConfig(config: Config, pixelsPerMillisecond: Pixels): Promise<Config> {
if (config.events == null) {

@@ -16,2 +29,7 @@ console.error('[DomainConfig] No events band in config!')

/**
* Wasm works in dev mode. When created into a lib, the deps are lazy loaded
* from the wrong dir (project root)
*/
// const orderEventsWasm = await import('../wasm/timeline_sort_events.js')

@@ -23,3 +41,3 @@ config.events.domains = config.events.domains.map(domainConfig => {

else if (domainConfig.orderedEvents == null) {
domainConfig.orderedEvents = orderEvents(domainConfig.events, pixelsPerMillisecond)
domainConfig.orderedEvents = orderEventsProxy(domainConfig.events, pixelsPerMillisecond)
delete domainConfig.events

@@ -26,0 +44,0 @@ }

@@ -5,7 +5,4 @@ import BandView from './index'

import { RawEv3nt } from '../../models/event';
import { logEvent } from '../../utils';
function formatDate(ts) {
const d = new Date(ts)
return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`
}
export default class EventsBandView extends BandView {

@@ -26,5 +23,5 @@ constructor(public band: EventsBand, private select: (e: RawEv3nt) => void) {

this.select(event)
console.log(event, formatDate(event.from), formatDate(event.to))
logEvent(event)
}
}
}
import createElement from '../../utils/create-element'
import props from '../../models/props'
import { DATE_BAR_HEIGHT, Pixels, EVENT_HEIGHT } from '../../constants'
import { DATE_BAR_HEIGHT, Pixels, EVENT_HEIGHT, PIXELS_PER_LETTER } from '../../constants'
import { findClosestRulerDate } from '../../utils'

@@ -28,3 +28,3 @@ import { labelBody } from '../../utils/dates'

constructor() {
animator.registerViewUpdaters(this.update)
animator.registerView(this)
this.offsiteCtx = this.offsiteCanvas.getContext('2d')

@@ -99,2 +99,3 @@ }

this.drawEvents()
this.drawEventsText()

@@ -117,16 +118,6 @@ props.minimapBands

props.eventsBand.domains.forEach(domain => {
const band = props.eventsBand
const left = band.positionAtTimestamp(band.from)
const offsetY = domain.topOffsetRatio * props.viewportHeight
const domainHeight = (domain.heightRatio * props.viewportHeight) - DATE_BAR_HEIGHT
for (const domain of props.eventsBand.domains) {
for (const event of domain.orderedEvents.events) {
event.left = band.positionAtTimestamp(event.from) - left
event.width = Math.round((event.time + event.space) * band.pixelsPerMillisecond)
if (event.width < 1) event.width = 1
event.top = offsetY + domainHeight - ((event.row + 1) * (EVENT_HEIGHT + 2))
if (event.from > props.eventsBand.to || event.to < props.eventsBand.from) continue
if (event.from > band.to || event.to < band.from) continue
if (!event.time) {

@@ -139,8 +130,6 @@ this.ctx.moveTo(event.left, event.top + EVENT_HEIGHT/2)

}
})
}
this.ctx.fillStyle = `rgba(126, 0, 0, .3)`
this.ctx.fill()
this.drawEventsText()
}

@@ -154,3 +143,3 @@

let eventWidth = event.width
let eventWidth = event.time === 0 ? event.padding : event.width
let eventLeft = event.left

@@ -163,4 +152,4 @@

if (event.label == null) event.label = 'NO LABEL'
if ((event.label.length * 8) + 10 < eventWidth) {
let eventLabelLength = event.label.length * PIXELS_PER_LETTER
if (eventLabelLength <= eventWidth) {
const paddingLeft = event.time ? 3 : 8

@@ -176,3 +165,3 @@ this.ctx.fillText(event.label, eventLeft + paddingLeft, event.top + EVENT_HEIGHT - 3)

const maxRowCount = band.domains.reduce((prev, curr) => {
const counts = curr.targets.map(index => props.eventsBand.domains[index].orderedEvents.rowCount)
const counts = curr.targets.map(index => props.eventsBand.domains[index].orderedEvents.row_count)
return Math.max(prev, ...counts)

@@ -179,0 +168,0 @@ }, 0)

{
"compilerOptions": {
"declaration": true,
"module": "commonjs",
"module": "esnext",
"moduleResolution": "node",
"noUnusedLocals": true,

@@ -6,0 +7,0 @@ "removeComments": true,

@@ -0,1 +1,2 @@

const path = require('path')
module.exports = {

@@ -5,2 +6,3 @@ entry: {

},
// entry: './src/index.ts',
output: {

@@ -12,6 +14,15 @@ filename: "[name].js",

globalObject: 'this',
publicPath: '/build/',
},
// output: {
// path: __dirname + "/build",
// // path: path.resolve(__dirname, 'build'),
// filename: "index.js",
// library: "Timeline",
// libraryTarget: "umd",
// globalObject: 'this',
// },
resolve: {
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: [".webpack.js", ".web.js", ".ts", ".tsx", ".js"]
extensions: [".webpack.js", ".web.js", ".ts", ".tsx", ".js", ".wasm"]
},

@@ -18,0 +29,0 @@ module: {

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc