timeline
Advanced tools
Comparing version 3.2.2 to 3.3.0
@@ -20,3 +20,3 @@ import { formatDate, Granularity } from '../src/utils/dates' | ||
test('DAY', () => { | ||
expect(formatDate(Date.UTC(1900, 0), "DAY")).toBe('Mon, 1st Jan 1900') | ||
expect(formatDate(Date.UTC(1900, 0), Granularity.DAY)).toBe('Mon, 1st Jan 1900') | ||
expect(formatDate(Date.UTC(1900, 11, 2), Granularity.DAY)).toBe('Sun, 2nd Dec 1900') | ||
@@ -23,0 +23,0 @@ expect(formatDate(Date.UTC(1900, 11, 3), Granularity.DAY)).toBe('Mon, 3rd Dec 1900') |
@@ -7,2 +7,3 @@ import { Milliseconds } from "./constants"; | ||
import EventsBand from "./models/band/events"; | ||
import Popup from './views/popup'; | ||
export declare type Multiplier = .25 | .5 | 1 | 2 | 4 | 8 | 16; | ||
@@ -24,3 +25,3 @@ export declare class Animator { | ||
registerModel(model: Band<MinimapBandConfig | EventsBandConfig>): void; | ||
registerView(view: Canvas | Debug): void; | ||
registerView(view: Canvas | Debug | Popup): void; | ||
private adjustMinimapBands; | ||
@@ -27,0 +28,0 @@ animate: (timestamp: number) => void; |
@@ -5,2 +5,3 @@ "use strict"; | ||
const constants_1 = require("./constants"); | ||
const event_bus_1 = require("./event-bus"); | ||
var Direction; | ||
@@ -51,3 +52,3 @@ (function (Direction) { | ||
this.adjustMinimapBands(); | ||
document.dispatchEvent(new CustomEvent(constants_1.ZOOM_DONE)); | ||
event_bus_1.default.dispatch(constants_1.EventType.ZoomDone); | ||
this.stop(); | ||
@@ -94,3 +95,3 @@ } | ||
this.elapsedTimeTotal = 0; | ||
document.dispatchEvent(new CustomEvent(constants_1.CENTER_CHANGE_DONE)); | ||
event_bus_1.default.dispatch(constants_1.EventType.CenterChange); | ||
} | ||
@@ -151,2 +152,3 @@ accelerate() { | ||
playForward() { | ||
event_bus_1.default.dispatch(constants_1.EventType.Play); | ||
this.direction = Direction.Forward; | ||
@@ -156,2 +158,3 @@ this.nextFrame(); | ||
playBackward() { | ||
event_bus_1.default.dispatch(constants_1.EventType.Play); | ||
this.direction = Direction.Backward; | ||
@@ -161,2 +164,3 @@ this.nextFrame(); | ||
stop() { | ||
event_bus_1.default.dispatch(constants_1.EventType.Pause); | ||
this.direction = Direction.Stop; | ||
@@ -163,0 +167,0 @@ this.activeBand = null; |
@@ -6,9 +6,8 @@ import { Animator } from './animator'; | ||
export default class Api { | ||
private onChange; | ||
protected views: View[]; | ||
animator: Animator; | ||
constructor(onChange: OnChangeFunction); | ||
private handleChange; | ||
constructor(); | ||
on(eventName: string, func: any): void; | ||
protected resize: () => void; | ||
reload(): void; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const animator_1 = require("./animator"); | ||
const props_1 = require("./models/props"); | ||
const constants_1 = require("./constants"); | ||
const props_1 = require("./models/props"); | ||
class Api { | ||
constructor(onChange) { | ||
this.onChange = onChange; | ||
constructor() { | ||
this.animator = animator_1.default; | ||
this.handleChange = () => { | ||
this.onChange(props_1.default); | ||
}; | ||
this.resize = () => { | ||
@@ -29,5 +25,22 @@ props_1.default.resize(); | ||
}); | ||
if (this.onChange != null && typeof this.onChange === 'function') { | ||
document.addEventListener(constants_1.CENTER_CHANGE_DONE, this.handleChange); | ||
document.addEventListener(constants_1.ZOOM_DONE, this.handleChange); | ||
} | ||
on(eventName, func) { | ||
const nameMap = { | ||
centerchange: constants_1.EventType.CenterChange, | ||
pause: constants_1.EventType.Pause, | ||
play: constants_1.EventType.Play, | ||
scrolldone: constants_1.EventType.ScrollDone, | ||
select: constants_1.EventType.Select, | ||
zoomdone: constants_1.EventType.ZoomDone, | ||
}; | ||
if (Object.keys(nameMap).indexOf(eventName) > -1) { | ||
const eventType = nameMap[eventName]; | ||
let realFunc; | ||
if (eventType === constants_1.EventType.CenterChange) | ||
realFunc = () => func(props_1.default); | ||
else if (eventType === constants_1.EventType.Select) | ||
realFunc = (ev) => func(ev.detail); | ||
else | ||
realFunc = func; | ||
document.addEventListener(eventType, realFunc); | ||
} | ||
@@ -34,0 +47,0 @@ } |
import { RawEv3nt } from "./models/event"; | ||
export declare const EVENT_HEIGHT = 14; | ||
export declare const EVENT_ROW_HEIGHT = 16; | ||
export declare const DATE_BAR_HEIGHT = 16; | ||
export declare const RULER_LABELS_HEIGHT = 60; | ||
export declare const CENTER_CHANGE_DONE = "CENTER_CHANGE_DONE"; | ||
export declare const ZOOM_DONE = "ZOOM_DONE"; | ||
export declare const SCROLL_DONE = "SCROLL_DONE"; | ||
export declare const IMAGE_SIZES: number[]; | ||
export declare const EVENT_HEIGHT = 16; | ||
export declare const LETTER_WIDTH: number; | ||
export declare const FONT_SIZE: number; | ||
export declare const ROW_SPACING: number; | ||
export declare const EVENT_ROW_HEIGHT: number; | ||
export declare const DATE_BAR_HEIGHT: number; | ||
export declare const IMAGE_BOUNDING_BOX: number; | ||
export declare const IMAGE_BORDER_SIZE: number; | ||
export declare const IMAGE_SIZE: number; | ||
export declare enum EventType { | ||
CenterChange = "CenterChange", | ||
ZoomDone = "ZoomDone", | ||
ScrollDone = "ScrollDone", | ||
Pause = "Pause", | ||
Play = "Play", | ||
Select = "Select" | ||
} | ||
export declare const PIXELS_PER_LETTER = 8; | ||
export declare const DEFAULT_IMAGE_PATH = "/images"; | ||
export declare type Milliseconds = number; | ||
@@ -11,0 +23,0 @@ export declare type Grid = [Milliseconds, Milliseconds][][]; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.EVENT_HEIGHT = 14; | ||
exports.EVENT_ROW_HEIGHT = 16; | ||
exports.IMAGE_SIZES = [16, 32, 64, 128, 256]; | ||
exports.EVENT_HEIGHT = 16; | ||
exports.LETTER_WIDTH = Math.round(exports.EVENT_HEIGHT * .1875 + 3.5); | ||
exports.FONT_SIZE = Math.round(exports.EVENT_HEIGHT * .3125 + 6); | ||
exports.ROW_SPACING = Math.round(exports.EVENT_HEIGHT / 3); | ||
exports.EVENT_ROW_HEIGHT = exports.EVENT_HEIGHT + exports.ROW_SPACING; | ||
exports.DATE_BAR_HEIGHT = exports.EVENT_ROW_HEIGHT; | ||
exports.RULER_LABELS_HEIGHT = 60; | ||
exports.CENTER_CHANGE_DONE = 'CENTER_CHANGE_DONE'; | ||
exports.ZOOM_DONE = 'ZOOM_DONE'; | ||
exports.SCROLL_DONE = 'SCROLL_DONE'; | ||
exports.IMAGE_BOUNDING_BOX = (exports.EVENT_ROW_HEIGHT * 2) - exports.ROW_SPACING * 2; | ||
exports.IMAGE_BORDER_SIZE = Math.round(exports.ROW_SPACING / 2); | ||
exports.IMAGE_SIZE = exports.IMAGE_SIZES.reduce((prev, curr) => Math.abs(curr - exports.IMAGE_BOUNDING_BOX) < Math.abs(prev - exports.IMAGE_BOUNDING_BOX) ? curr : prev); | ||
var EventType; | ||
(function (EventType) { | ||
EventType["CenterChange"] = "CenterChange"; | ||
EventType["ZoomDone"] = "ZoomDone"; | ||
EventType["ScrollDone"] = "ScrollDone"; | ||
EventType["Pause"] = "Pause"; | ||
EventType["Play"] = "Play"; | ||
EventType["Select"] = "Select"; | ||
})(EventType = exports.EventType || (exports.EventType = {})); | ||
exports.PIXELS_PER_LETTER = 8; | ||
exports.DEFAULT_IMAGE_PATH = '/images'; | ||
class RawSegment { | ||
@@ -12,0 +25,0 @@ } |
@@ -0,4 +1,6 @@ | ||
import { EventType } from './constants'; | ||
export declare type Target = Document | Window | HTMLElement; | ||
export declare class EventBus { | ||
private eventsListeners; | ||
dispatch(eventType: EventType, payload?: any): void; | ||
register(type: string, listener: EventListenerOrEventListenerObject, target?: Target): void; | ||
@@ -5,0 +7,0 @@ flush(): void; |
@@ -7,2 +7,8 @@ "use strict"; | ||
} | ||
dispatch(eventType, payload) { | ||
const event = (payload != null) ? | ||
new CustomEvent(eventType, { detail: payload }) : | ||
new CustomEvent(eventType); | ||
document.dispatchEvent(event); | ||
} | ||
register(type, listener, target = document) { | ||
@@ -9,0 +15,0 @@ target.addEventListener(type, listener); |
import { Props } from './models/props'; | ||
import Config from './models/config/index'; | ||
import { calcPixelsPerMillisecond } from './utils'; | ||
import { OrderedEvents, orderEvents } from './utils/events.worker'; | ||
import Api, { OnChangeFunction } from './api'; | ||
import { OrderedTimeline, orderEvents } from './utils/events.worker'; | ||
import Api from './api'; | ||
import MinimapBand from './models/band/minimap'; | ||
import EventsBand from './models/band/events'; | ||
import { formatDate } from './utils/dates'; | ||
import { RawEv3nt } from './models/event'; | ||
export { Config as TimelineConfig, Props as TimelineProps, EventsBand, MinimapBand, OrderedEvents, calcPixelsPerMillisecond, formatDate, orderEvents, RawEv3nt }; | ||
export declare type OnSelectFunction = (e: RawEv3nt) => void; | ||
import { Ev3ntLocation, RawEv3nt, Ev3nt, Voyage } from './models/event'; | ||
import { EventType } from './constants'; | ||
export { Config as TimelineConfig, Ev3nt, Ev3ntLocation, EventsBand, EventType, MinimapBand, OrderedTimeline, Props as TimelineProps, RawEv3nt, calcPixelsPerMillisecond, formatDate, orderEvents, Voyage, }; | ||
export declare type OnSelectFunction = (e: Ev3nt, band: EventsBand, props: Props) => void; | ||
export default class Timeline extends Api { | ||
protected config: Config; | ||
private onSelect?; | ||
private wrapper; | ||
constructor(config: Config, onChange?: OnChangeFunction, onSelect?: OnSelectFunction); | ||
private popup; | ||
constructor(config: Config); | ||
hidePopup(): void; | ||
showPopup(event: Ev3nt): void; | ||
private render; | ||
@@ -18,0 +20,0 @@ private renderLabels; |
@@ -12,3 +12,3 @@ "use strict"; | ||
const events_worker_1 = require("./utils/events.worker"); | ||
exports.OrderedEvents = events_worker_1.OrderedEvents; | ||
exports.OrderedTimeline = events_worker_1.OrderedTimeline; | ||
exports.orderEvents = events_worker_1.orderEvents; | ||
@@ -19,2 +19,3 @@ const api_1 = require("./api"); | ||
const label_1 = require("./views/label"); | ||
const popup_1 = require("./views/popup"); | ||
const minimap_1 = require("./models/band/minimap"); | ||
@@ -27,9 +28,12 @@ exports.MinimapBand = minimap_1.default; | ||
const event_1 = require("./models/event"); | ||
exports.Ev3ntLocation = event_1.Ev3ntLocation; | ||
exports.RawEv3nt = event_1.RawEv3nt; | ||
exports.Ev3nt = event_1.Ev3nt; | ||
exports.Voyage = event_1.Voyage; | ||
const band_2 = require("./models/band"); | ||
const constants_1 = require("./constants"); | ||
exports.EventType = constants_1.EventType; | ||
class Timeline extends api_1.default { | ||
constructor(config, onChange, onSelect) { | ||
super(onChange); | ||
this.config = config; | ||
this.onSelect = onSelect; | ||
constructor(config) { | ||
super(); | ||
this.appendToWrapper = (child) => { | ||
@@ -43,5 +47,12 @@ let children = child.render(); | ||
config.rootElement.appendChild(this.render()); | ||
this.popup = new popup_1.default(this.wrapper); | ||
const debouncedResize = utils_1.debounce(this.resize, 600); | ||
window.addEventListener('resize', debouncedResize); | ||
} | ||
hidePopup() { | ||
this.popup.hide(); | ||
} | ||
showPopup(event) { | ||
this.popup.show(event); | ||
} | ||
render() { | ||
@@ -58,3 +69,3 @@ this.wrapper = create_element_1.default('div', 'wrapper', [ | ||
.map(band => band.type === band_2.BandType.EventsBand ? | ||
new events_1.default(band, this.onSelect) : | ||
new events_1.default(band) : | ||
new band_1.default(band)); | ||
@@ -61,0 +72,0 @@ this.views.push(new canvas_1.default()); |
import Band, { BandType } from '.'; | ||
import { EventsBandConfig } from '../config'; | ||
import { Pixels } from '../../constants'; | ||
import { RawEv3nt } from '../event'; | ||
import { Ev3nt } from '../event'; | ||
import { OrderedBand } from '../../utils/events.worker'; | ||
export default class EventsBand extends Band<EventsBandConfig> { | ||
@@ -10,15 +11,15 @@ type: BandType; | ||
private highestVisibleRow; | ||
events: RawEv3nt[]; | ||
events: Ev3nt[]; | ||
rowCount: number; | ||
visibleEvents: RawEv3nt[]; | ||
visibleEvents: Ev3nt[]; | ||
private _offsetY; | ||
offsetY: number; | ||
constructor(config: EventsBandConfig); | ||
init(): void; | ||
init(orderedBand: OrderedBand): void; | ||
private getColor; | ||
private updateEvents; | ||
update(): void; | ||
getEventByCoordinates(x: Pixels, y: Pixels): RawEv3nt; | ||
getEventByCoordinates(x: Pixels, y: Pixels): Ev3nt; | ||
zoomIn(): void; | ||
zoomOut(): void; | ||
} |
@@ -8,5 +8,3 @@ "use strict"; | ||
const props_1 = require("../props"); | ||
const events_worker_1 = require("../../utils/events.worker"); | ||
const dates_1 = require("../../utils/dates"); | ||
const utils_1 = require("../../utils"); | ||
class EventsBand extends _1.default { | ||
@@ -37,10 +35,6 @@ constructor(config) { | ||
} | ||
init() { | ||
init(orderedBand) { | ||
super.init(); | ||
const pixelsPerMillisecond = utils_1.calcPixelsPerMillisecond(props_1.default.viewportWidth, this.config.zoomLevel || 0, props_1.default.time); | ||
const orderedEvents = this.config.orderedEvents == null ? | ||
events_worker_1.orderEvents(this.config.events, pixelsPerMillisecond) : | ||
this.config.orderedEvents; | ||
this.events = orderedEvents.events; | ||
this.rowCount = orderedEvents.row_count; | ||
this.events = orderedBand.events; | ||
this.rowCount = orderedBand.rowCount; | ||
this.height = constants_1.EVENT_ROW_HEIGHT * this.rowCount; | ||
@@ -82,3 +76,36 @@ this.offsetY = 0; | ||
event.width = 1; | ||
event.padding = Math.round((event.space) * this.pixelsPerMillisecond); | ||
event.uncertain_from_width = 0; | ||
if (event.dmin != null) { | ||
let uncertain_from_to; | ||
if (event.d != null) { | ||
uncertain_from_to = event.d; | ||
} | ||
else if (event.ed != null) { | ||
uncertain_from_to = event.ed; | ||
} | ||
else if (event.dmax != null) { | ||
uncertain_from_to = event.dmin + (event.dmax - event.dmin) / 2; | ||
} | ||
else { | ||
throw Error(['updateEvents', 'Width uncertain from is not definable', JSON.stringify(event)].join('\n')); | ||
} | ||
event.uncertain_from_width = (uncertain_from_to - event.dmin) * this.pixelsPerMillisecond; | ||
} | ||
event.uncertain_to_width = 0; | ||
if (event.dmax != null) { | ||
let uncertain_to_from; | ||
if (event.ed != null) { | ||
uncertain_to_from = event.ed; | ||
} | ||
else if (event.d != null) { | ||
uncertain_to_from = event.d; | ||
} | ||
else if (event.dmin != null) { | ||
uncertain_to_from = event.dmin + (event.dmax - event.dmin) / 2; | ||
} | ||
else { | ||
throw Error(['updateEvents', 'Width uncertain to is not definable', JSON.stringify(event)].join('\n')); | ||
} | ||
event.uncertain_to_width = (event.dmax - uncertain_to_from) * this.pixelsPerMillisecond; | ||
} | ||
event.top = this.top + this.availableHeight - ((event.row + 1) * constants_1.EVENT_ROW_HEIGHT) + this.offsetY; | ||
@@ -98,3 +125,3 @@ event.color = this.getColor(event.from, event.to); | ||
const event = this.events.find(e => { | ||
if (!(e.from < timestamp && e.from + e.time + e.space > timestamp) || | ||
if (!(e.from < timestamp && e.screenTo > timestamp) || | ||
(e.row < this.lowestVisibleRow || e.row > this.highestVisibleRow)) | ||
@@ -101,0 +128,0 @@ return false; |
import { Granularity } from '../../utils/dates'; | ||
import { Pixels, Milliseconds, Ratio } from '../../constants'; | ||
import { BandConfig } from '../config'; | ||
import { OrderedBand } from '../../utils/events.worker'; | ||
export declare enum BandType { | ||
@@ -33,3 +34,3 @@ EventsBand = 0, | ||
private setHorizontalProps; | ||
init(): void; | ||
init(_orderedBand?: OrderedBand): void; | ||
resize(): void; | ||
@@ -36,0 +37,0 @@ update(): void; |
@@ -40,2 +40,4 @@ "use strict"; | ||
this.availableHeight = this.visibleHeight - constants_1.DATE_BAR_HEIGHT; | ||
if (this.availableHeight / this.visibleHeight < .666) | ||
this.availableHeight = this.visibleHeight * .666; | ||
this.visibleRowsCount = Math.floor(this.availableHeight / constants_1.EVENT_ROW_HEIGHT) - 1; | ||
@@ -49,3 +51,3 @@ this.top = Math.round(this.config.topOffsetRatio * props_1.default.viewportHeight); | ||
} | ||
init() { | ||
init(_orderedBand) { | ||
this.zoomLevel = this.config.zoomLevel; | ||
@@ -52,0 +54,0 @@ this.setVerticalProps(); |
@@ -56,11 +56,14 @@ "use strict"; | ||
continue; | ||
const x = this.positionAtTimestamp(event.from); | ||
const y = this.maxRowCount - ((event.row + 2) * this.eventHeight); | ||
const eventWidth = Math.round(event.time * this.pixelsPerMillisecond); | ||
const eventLeft = this.positionAtTimestamp(event.date_min != null ? event.date_min : event.date); | ||
const y = this.maxRowCount - ((event.row + 1) * this.eventHeight); | ||
const width = eventWidth < 1 ? 1 : eventWidth; | ||
this.nextCtx.rect(eventLeft, y, width, this.eventHeight); | ||
this.nextCtx.fillStyle = `rgb(190, 190, 190)`; | ||
this.nextCtx.fillRect(x, y, width, this.eventHeight); | ||
if (event.img) { | ||
this.nextCtx.fillStyle = `rgb(240, 240, 240)`; | ||
this.nextCtx.fillRect(x, y - this.eventHeight * 2, this.eventHeight * 2, this.eventHeight * 2); | ||
} | ||
} | ||
}); | ||
this.nextCtx.fillStyle = `rgb(190, 190, 190)`; | ||
this.nextCtx.fill(); | ||
} | ||
@@ -67,0 +70,0 @@ updateNextCanvas() { |
import { Ratio } from "../../constants"; | ||
import { OrderedEvents } from "../../utils/events.worker"; | ||
import { RawEv3nt } from "../event"; | ||
import { OrderedTimeline } from "../../utils/events.worker"; | ||
import { RawEv3nt, Ev3nt } from "../event"; | ||
import MinimapBand from "../band/minimap"; | ||
@@ -22,9 +22,11 @@ import EventsBand from "../band/events"; | ||
label?: string; | ||
orderedEvents?: OrderedEvents; | ||
orderedEvents?: OrderedTimeline; | ||
} | ||
export default class Config { | ||
bands: (EventsBand | MinimapBand)[]; | ||
center?: number; | ||
controlBand: EventsBand; | ||
bands: (EventsBand | MinimapBand)[]; | ||
controlBand?: EventsBand; | ||
imagePath?: string; | ||
parent?: Ev3nt; | ||
rootElement: HTMLElement; | ||
} |
import { Milliseconds, Pixels } from '../constants'; | ||
import { Granularity } from '../utils/dates'; | ||
export declare enum ImageFileType { | ||
NONE = "none", | ||
JPG = "jpg", | ||
SVG = "svg", | ||
GIF = "gif", | ||
PNG = "png" | ||
} | ||
declare class Point { | ||
type: "Point"; | ||
coordinates: [number, number]; | ||
} | ||
export declare class Ev3ntLocation { | ||
coor: Point; | ||
coor4326?: [number, number]; | ||
dmin?: Milliseconds; | ||
dmin_g?: Granularity; | ||
d?: Milliseconds; | ||
d_g?: Granularity; | ||
ed?: Milliseconds; | ||
ed_g?: Granularity; | ||
dmax?: Milliseconds; | ||
dmax_g?: Granularity; | ||
} | ||
export declare class Voyage { | ||
d: Milliseconds; | ||
ed: Milliseconds; | ||
route: string; | ||
sp?: Point; | ||
ep?: Point; | ||
} | ||
export declare class RawEv3nt { | ||
date: Milliseconds; | ||
date_granularity?: Granularity; | ||
date_min?: Milliseconds; | ||
date_min_granularity?: Granularity; | ||
description?: string; | ||
end_date?: Milliseconds; | ||
end_date_granularity?: Granularity; | ||
end_date_max?: Milliseconds; | ||
end_date_max_granularity?: Granularity; | ||
id?: string; | ||
label?: string; | ||
row?: number; | ||
wikidata_identifier?: string; | ||
class: string[]; | ||
d: Milliseconds; | ||
d_g: Granularity; | ||
dmax: Milliseconds; | ||
dmax_g: Granularity; | ||
dmin: Milliseconds; | ||
dmin_g: Granularity; | ||
dsc: string; | ||
ed: Milliseconds; | ||
ed_g: Granularity; | ||
id: string; | ||
img: ImageFileType; | ||
lbl: string; | ||
locs: Ev3ntLocation[]; | ||
voyages: Voyage[]; | ||
wid: string; | ||
} | ||
export declare class Ev3nt extends RawEv3nt { | ||
from: Milliseconds; | ||
to: Milliseconds; | ||
tags: string[]; | ||
locations: any[]; | ||
screenTo: Milliseconds; | ||
time?: Milliseconds; | ||
space?: Milliseconds; | ||
row: number; | ||
left?: Pixels; | ||
padding?: Pixels; | ||
top?: Pixels; | ||
width?: Pixels; | ||
uncertain_from_width?: Pixels; | ||
uncertain_to_width?: Pixels; | ||
color?: string; | ||
image?: HTMLImageElement; | ||
constructor(event: RawEv3nt, pixelsPerMillisecond?: Pixels); | ||
} | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const constants_1 = require("../constants"); | ||
var ImageFileType; | ||
(function (ImageFileType) { | ||
ImageFileType["NONE"] = "none"; | ||
ImageFileType["JPG"] = "jpg"; | ||
ImageFileType["SVG"] = "svg"; | ||
ImageFileType["GIF"] = "gif"; | ||
ImageFileType["PNG"] = "png"; | ||
})(ImageFileType = exports.ImageFileType || (exports.ImageFileType = {})); | ||
class Point { | ||
} | ||
class Ev3ntLocation { | ||
} | ||
exports.Ev3ntLocation = Ev3ntLocation; | ||
class Voyage { | ||
} | ||
exports.Voyage = Voyage; | ||
class RawEv3nt { | ||
constructor() { | ||
this.date_granularity = "DAY"; | ||
} | ||
exports.RawEv3nt = RawEv3nt; | ||
class Ev3nt extends RawEv3nt { | ||
constructor(event, pixelsPerMillisecond) { | ||
super(); | ||
for (const key in event) { | ||
if (event[key] != null) | ||
this[key] = event[key]; | ||
} | ||
if (this.lbl == null) | ||
this.lbl = 'NO LABEL'; | ||
if (this.id == null) | ||
this.id = 'id_' + crypto.getRandomValues(new Uint8Array(4)).join('_'); | ||
this.from = this.dmin || this.d; | ||
this.to = this.dmax || this.ed; | ||
if (this.to == null) | ||
this.to = this.from; | ||
this.time = this.to - this.from; | ||
if (pixelsPerMillisecond != null) { | ||
const paddingRight = Math.round(constants_1.EVENT_HEIGHT * 2 / pixelsPerMillisecond); | ||
let space = ((this.lbl.length * constants_1.PIXELS_PER_LETTER) / pixelsPerMillisecond) + paddingRight; | ||
space = space > this.time ? space - this.time : 0; | ||
this.screenTo = Math.round(this.from + this.time + space); | ||
} | ||
} | ||
} | ||
exports.RawEv3nt = RawEv3nt; | ||
exports.Ev3nt = Ev3nt; |
@@ -5,4 +5,6 @@ import { Milliseconds, Pixels } from "../constants"; | ||
import EventsBand from "./band/events"; | ||
import { RawEv3nt } from './event'; | ||
export declare class Props { | ||
private readonly defaultCenterRatio; | ||
parent: RawEv3nt; | ||
bands: (EventsBand | MinimapBand)[]; | ||
@@ -12,2 +14,3 @@ eventsBands: EventsBand[]; | ||
controlBand: EventsBand; | ||
imagePath: string; | ||
from: Milliseconds; | ||
@@ -23,3 +26,2 @@ time: Milliseconds; | ||
dimensions: HTMLElement; | ||
private centerChangeDone; | ||
init(config: Config): void; | ||
@@ -26,0 +28,0 @@ resize(): void; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const constants_1 = require("../constants"); | ||
const utils_1 = require("../utils"); | ||
const band_1 = require("./band"); | ||
const __1 = require(".."); | ||
const event_bus_1 = require("../event-bus"); | ||
function onEventsBand(band) { | ||
@@ -15,5 +16,2 @@ return band.type === band_1.BandType.EventsBand; | ||
this.defaultCenterRatio = .5; | ||
this.centerChangeDone = utils_1.debounce(() => { | ||
document.dispatchEvent(new CustomEvent(constants_1.CENTER_CHANGE_DONE)); | ||
}, 300); | ||
} | ||
@@ -30,3 +28,3 @@ get center() { return this._center; } | ||
this._center = n; | ||
this.centerChangeDone(); | ||
event_bus_1.default.dispatch(constants_1.EventType.CenterChange); | ||
} | ||
@@ -42,21 +40,5 @@ set dimensions(rootElement) { | ||
console.error('[init] No rootElement found'); | ||
this.imagePath = config.imagePath != null ? config.imagePath : constants_1.DEFAULT_IMAGE_PATH; | ||
this.rootElement = config.rootElement; | ||
this.dimensions = this.rootElement; | ||
const [froms, tos] = config.bands.reduce((prev, curr) => { | ||
if (curr.type === band_1.BandType.MinimapBand) | ||
return prev; | ||
const band = curr; | ||
const events = band.config.orderedEvents == null ? band.config.events : band.config.orderedEvents.events; | ||
prev[0].push(events[0].date_min || events[0].date); | ||
prev[1].push(events.reduce((prev2, curr2) => { | ||
return Math.max(prev2, curr2.end_date || -Infinity, curr2.end_date_max || -Infinity); | ||
}, -Infinity)); | ||
return prev; | ||
}, [[], []]); | ||
this.from = Math.min(...froms); | ||
this.to = Math.max(...tos); | ||
this.time = this.to - this.from; | ||
this.center = (config.center != null) ? | ||
config.center : | ||
this.from + (this.defaultCenterRatio * this.time); | ||
this.bands = config.bands; | ||
@@ -66,3 +48,26 @@ this.eventsBands = this.bands.filter(onEventsBand); | ||
this.controlBand = config.controlBand != null ? config.controlBand : this.eventsBands[0]; | ||
for (const band of this.bands) { | ||
const t0 = performance.now(); | ||
const options = { | ||
bands: this.eventsBands | ||
.map(band => ({ | ||
events: band.config.events, | ||
zoomLevel: band.config.zoomLevel | ||
})), | ||
parent: config.parent, | ||
viewportWidth: this.viewportWidth | ||
}; | ||
const orderResult = __1.orderEvents(options); | ||
this.parent = orderResult.parent; | ||
this.from = orderResult.from; | ||
this.to = orderResult.to; | ||
this.time = orderResult.time; | ||
const t1 = performance.now(); | ||
console.log('Performance: ', `${t1 - t0}ms\n[from] ${new Date(this.from).toUTCString()}\n[ to ] ${new Date(this.to).toUTCString()}`); | ||
this.center = (config.center != null) ? | ||
config.center : | ||
this.from + (this.defaultCenterRatio * this.time); | ||
for (const [index, band] of this.eventsBands.entries()) { | ||
band.init(orderResult.bands[index]); | ||
} | ||
for (const band of this.minimapBands) { | ||
band.init(); | ||
@@ -69,0 +74,0 @@ } |
@@ -14,3 +14,3 @@ import { Milliseconds } from "../constants"; | ||
WEEK = "WEEK", | ||
MONTH = "MONHT", | ||
MONTH = "MONTH", | ||
YEAR = "YEAR", | ||
@@ -28,3 +28,3 @@ YEAR_5 = "YEAR_5", | ||
export declare function subsequentDate(granularity: Granularity): ((date: Milliseconds) => Milliseconds); | ||
export declare function byDate(a: RawEv3nt, b: RawEv3nt): 1 | 0 | -1; | ||
export declare function byDate(a: RawEv3nt, b: RawEv3nt): 0 | 1 | -1; | ||
export declare const labelBody: (d: number, granularity: Granularity) => string; |
@@ -33,3 +33,3 @@ "use strict"; | ||
label = `${formatMonth(date)} ${label}`; | ||
if (granularity === "MONHT") | ||
if (granularity === "MONTH") | ||
return label; | ||
@@ -72,3 +72,3 @@ label = `${formatDateNumber(date)} ${label}`; | ||
if (pixelsPerMillisecond > 2.2e-8) | ||
return "MONHT"; | ||
return "MONTH"; | ||
if (pixelsPerMillisecond > 2.2e-9) | ||
@@ -82,3 +82,3 @@ return "YEAR"; | ||
return "DECADE_5"; | ||
if (pixelsPerMillisecond > 1e-11) | ||
if (pixelsPerMillisecond > 1.5e-11) | ||
return "CENTURY"; | ||
@@ -136,3 +136,3 @@ if (pixelsPerMillisecond > 5e-12) | ||
} | ||
if (granularity === "MONHT") { | ||
if (granularity === "MONTH") { | ||
return (d) => { | ||
@@ -186,4 +186,4 @@ const date = new Date(d); | ||
function byDate(a, b) { | ||
const aFrom = a.date_min != null ? a.date_min : a.date; | ||
const bFrom = b.date_min != null ? b.date_min : b.date; | ||
const aFrom = a.dmin != null ? a.dmin : a.d; | ||
const bFrom = b.dmin != null ? b.dmin : b.d; | ||
if (aFrom < bFrom) | ||
@@ -193,4 +193,4 @@ return -1; | ||
return 1; | ||
const aTo = a.end_date_max != null ? a.end_date_max : a.end_date; | ||
const bTo = b.end_date_max != null ? b.end_date_max : b.end_date; | ||
const aTo = a.dmax != null ? a.dmax : a.ed; | ||
const bTo = b.dmax != null ? b.dmax : b.ed; | ||
if (aTo < bTo) | ||
@@ -214,3 +214,3 @@ return -1; | ||
return date.getUTCFullYear().toString(); | ||
if (granularity === "MONHT") | ||
if (granularity === "MONTH") | ||
return formatMonth(date); | ||
@@ -217,0 +217,0 @@ if (granularity === "WEEK") |
@@ -1,7 +0,26 @@ | ||
import { Milliseconds } from "../constants"; | ||
import { RawEv3nt } from "../models/event"; | ||
export declare class OrderedEvents { | ||
import { Milliseconds, Pixels } from "../constants"; | ||
import { Ev3nt, RawEv3nt } from "../models/event"; | ||
interface InputBand { | ||
events: RawEv3nt[]; | ||
row_count: number; | ||
zoomLevel: number; | ||
} | ||
export declare function orderEvents(events: RawEv3nt[], pixelsPerMillisecond: Milliseconds): OrderedEvents; | ||
export interface OrderedBand { | ||
events: Ev3nt[]; | ||
pixelsPerMillisecond?: Pixels; | ||
rowCount: number; | ||
zoomLevel: number; | ||
} | ||
interface Options { | ||
parent?: RawEv3nt; | ||
bands: InputBand[]; | ||
viewportWidth: Pixels; | ||
} | ||
export declare class OrderedTimeline { | ||
bands: OrderedBand[]; | ||
from: Milliseconds; | ||
parent: Ev3nt; | ||
time: Milliseconds; | ||
to: Milliseconds; | ||
} | ||
export declare function orderEvents(options: Options): OrderedTimeline; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const constants_1 = require("../constants"); | ||
class OrderedEvents { | ||
constructor() { | ||
this.events = []; | ||
this.row_count = 0; | ||
const event_1 = require("../models/event"); | ||
const index_1 = require("./index"); | ||
class OrderedTimeline { | ||
} | ||
exports.OrderedTimeline = OrderedTimeline; | ||
function orderEvents(options) { | ||
if (options.bands == null || !options.bands.length) | ||
return new OrderedTimeline(); | ||
let from = options.bands.reduce((prev, curr) => { | ||
const firstEvent = curr.events[0]; | ||
return Math.min(prev, firstEvent.dmin || Infinity, firstEvent.d || Infinity); | ||
}, Infinity); | ||
let to = options.bands.reduce((prev, curr) => { | ||
const highest = curr.events.reduce((prev2, curr2) => { | ||
return Math.max(prev2, curr2.d || -Infinity, curr2.ed || -Infinity, curr2.dmax || -Infinity); | ||
}, -Infinity); | ||
return Math.max(highest, prev); | ||
}, -Infinity); | ||
let parent; | ||
if (options.parent != null) { | ||
parent = new event_1.Ev3nt(options.parent); | ||
from = Math.min(from, parent.dmin || Infinity, parent.d || Infinity); | ||
to = Math.max(to, parent.ed || -Infinity, parent.dmax || -Infinity); | ||
} | ||
} | ||
exports.OrderedEvents = OrderedEvents; | ||
const pixelsPerLetter = 8; | ||
function orderEvents(events, pixelsPerMillisecond) { | ||
if (!events.length) | ||
return new OrderedEvents(); | ||
let rowCount = 0; | ||
const grid = []; | ||
const paddingRight = constants_1.EVENT_HEIGHT * 2 / pixelsPerMillisecond; | ||
const addRow = (event) => { | ||
let row; | ||
if (event.label == null) | ||
event.label = 'NO LABEL'; | ||
event.from = event.date_min || event.date; | ||
event.to = event.end_date_max || event.end_date; | ||
if (event.to == null) | ||
event.to = event.from; | ||
event.time = event.to == null ? 0 : event.to - event.from; | ||
event.space = 0; | ||
if (!event.time) { | ||
if (event.label == null) | ||
event.label = 'NO LABEL'; | ||
event.space = ((event.label.length * pixelsPerLetter) / pixelsPerMillisecond) + paddingRight; | ||
const time = to - from; | ||
function processBand(band) { | ||
const pixelsPerMillisecond = index_1.calcPixelsPerMillisecond(options.viewportWidth, band.zoomLevel, time); | ||
const rows = [-Infinity]; | ||
const imageSize = Math.round(constants_1.EVENT_ROW_HEIGHT * 2 / pixelsPerMillisecond); | ||
function rowHasSpace(row, imageFrom) { | ||
return (rows[row + 1] == null || rows[row + 1] < imageFrom) && (rows[row + 2] == null || rows[row + 2] < imageFrom); | ||
} | ||
let rowIterator = 0; | ||
while (row == null && rowIterator < grid.length) { | ||
let cellIterator = 0; | ||
let hasSpace = true; | ||
while (hasSpace && cellIterator < grid[rowIterator].length) { | ||
if (event.to < grid[rowIterator][cellIterator][0]) | ||
break; | ||
hasSpace = event.from > grid[rowIterator][cellIterator][1]; | ||
cellIterator++; | ||
function addRow(rawEvent) { | ||
const event = new event_1.Ev3nt(rawEvent, pixelsPerMillisecond); | ||
let row; | ||
if (event.img) { | ||
const imageFrom = event.time ? event.from : event.from - imageSize / 2; | ||
const imageTo = event.time ? event.from + imageSize : event.from + imageSize / 2; | ||
row = rows.findIndex(r => imageFrom > r); | ||
if (row > -1) { | ||
let hasSpace = false; | ||
while (!hasSpace) { | ||
hasSpace = rowHasSpace(row, imageFrom); | ||
if (hasSpace) | ||
break; | ||
row = rows.findIndex((r, i) => i > row && imageFrom > r); | ||
if (row === -1) | ||
hasSpace = true; | ||
} | ||
} | ||
if (row === -1) { | ||
row = rows.push(event.screenTo) - 1; | ||
rows.push(imageTo); | ||
rows.push(imageTo); | ||
} | ||
else { | ||
rows[row] = event.screenTo; | ||
rows[row + 1] = imageTo; | ||
rows[row + 2] = imageTo; | ||
} | ||
} | ||
if (hasSpace) { | ||
grid[rowIterator].push([event.from, event.from + event.time + event.space]); | ||
row = rowIterator; | ||
else { | ||
row = rows.findIndex(r => event.from > r); | ||
if (row === -1) { | ||
row = rows.push(event.screenTo) - 1; | ||
} | ||
else { | ||
rows[row] = event.screenTo; | ||
} | ||
} | ||
rowIterator++; | ||
event.row = row; | ||
return event; | ||
} | ||
if (row == null) | ||
row = grid.push([[event.from, event.from + event.time + event.space]]) - 1; | ||
if (row > rowCount) | ||
rowCount = row; | ||
event.row = row; | ||
return event; | ||
}; | ||
events = events.map(addRow); | ||
return { | ||
events: band.events.map(addRow), | ||
zoomLevel: band.zoomLevel, | ||
pixelsPerMillisecond, | ||
rowCount: rows.length, | ||
}; | ||
} | ||
return { | ||
events, | ||
row_count: grid.length | ||
bands: options.bands.map(processBand), | ||
from, | ||
parent, | ||
time, | ||
to, | ||
}; | ||
} | ||
exports.orderEvents = orderEvents; |
@@ -1,2 +0,2 @@ | ||
import { RawEv3nt } from "../models/event"; | ||
import { Ev3nt } from "../models/event"; | ||
import { Milliseconds, Ratio, Pixels } from "../constants"; | ||
@@ -8,2 +8,2 @@ export declare const debounce: (func: Function, wait: number) => () => void; | ||
export declare function calcPixelsPerMillisecond(viewportWidth: Pixels, zoomLevel: number, totalTime: Milliseconds): number; | ||
export declare function logEvent(event: RawEv3nt, ...rest: string[]): void; | ||
export declare function logEvent(event: Ev3nt, ...rest: string[]): void; |
@@ -37,7 +37,7 @@ "use strict"; | ||
const d = new Date(ts); | ||
return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`; | ||
return d.toUTCString(); | ||
} | ||
function logEvent(event, ...rest) { | ||
console.log(event.label, event, event.left, formatDate(event.from), formatDate(event.to), rest); | ||
console.log(event.lbl, event, formatDate(event.from), formatDate(event.to), rest); | ||
} | ||
exports.logEvent = logEvent; |
import BandView from './index'; | ||
import EventsBand from '../../models/band/events'; | ||
import { OnSelectFunction } from '../../index'; | ||
export default class EventsBandView extends BandView { | ||
band: EventsBand; | ||
private select; | ||
constructor(band: EventsBand, select: OnSelectFunction); | ||
constructor(band: EventsBand); | ||
render(): HTMLElement; | ||
@@ -9,0 +7,0 @@ private onWheel; |
@@ -5,8 +5,7 @@ "use strict"; | ||
const event_bus_1 = require("../../event-bus"); | ||
const utils_1 = require("../../utils"); | ||
const constants_1 = require("../../constants"); | ||
class EventsBandView extends index_1.default { | ||
constructor(band, select) { | ||
constructor(band) { | ||
super(band); | ||
this.band = band; | ||
this.select = select; | ||
this.onWheel = (ev) => { | ||
@@ -24,6 +23,3 @@ if (Math.abs(ev.deltaX) === 0 && ev.deltaY !== 0) { | ||
const event = this.band.getEventByCoordinates(ev.clientX, ev.clientY); | ||
if (event && this.select) { | ||
this.select(event); | ||
utils_1.logEvent(event); | ||
} | ||
event_bus_1.default.dispatch(constants_1.EventType.Select, event); | ||
}; | ||
@@ -30,0 +26,0 @@ } |
@@ -71,3 +71,3 @@ "use strict"; | ||
if (this.lastDragInterval > 200 || significantDrag) { | ||
document.dispatchEvent(new CustomEvent(constants_1.SCROLL_DONE)); | ||
event_bus_1.default.dispatch(constants_1.EventType.ScrollDone); | ||
} | ||
@@ -74,0 +74,0 @@ } |
@@ -9,2 +9,6 @@ import View from '../index'; | ||
constructor(); | ||
private updateImages; | ||
private onImgLoad; | ||
private drawImage; | ||
private onAnimationDone; | ||
render(): HTMLCanvasElement[]; | ||
@@ -11,0 +15,0 @@ resize(): void; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const tslib_1 = require("tslib"); | ||
const create_element_1 = require("../../utils/create-element"); | ||
@@ -8,18 +9,72 @@ const props_1 = require("../../models/props"); | ||
const rulers_1 = require("./rulers"); | ||
const band_1 = require("../../models/band"); | ||
const event_bus_1 = require("../../event-bus"); | ||
class Canvas { | ||
constructor() { | ||
this.indicatorsDrawn = false; | ||
this.onImgLoad = (event) => { | ||
const callback = (ev) => { | ||
event.image.removeEventListener('load', callback); | ||
event.image.removeEventListener('error', callback); | ||
if (ev.type === 'error') { | ||
event.image = null; | ||
return; | ||
} | ||
if (event.image.width > event.image.height) { | ||
event.image.height = Math.round(event.image.height * (constants_1.IMAGE_BOUNDING_BOX / event.image.width)); | ||
event.image.width = constants_1.IMAGE_BOUNDING_BOX; | ||
} | ||
else { | ||
event.image.width = Math.round(event.image.width * (constants_1.IMAGE_BOUNDING_BOX / event.image.height)); | ||
event.image.height = constants_1.IMAGE_BOUNDING_BOX; | ||
} | ||
this.drawImage(event); | ||
}; | ||
return callback; | ||
}; | ||
this.onAnimationDone = () => { | ||
}; | ||
this.update = () => { | ||
props_1.default.bands | ||
.forEach(band => { | ||
if (band.type === band_1.BandType.EventsBand) | ||
this.drawEventsBand(band); | ||
else | ||
this.drawMinimapBand(band); | ||
}); | ||
for (const band of props_1.default.eventsBands) { | ||
this.drawEventsBand(band); | ||
} | ||
for (const band of props_1.default.minimapBands) { | ||
this.drawMinimapBand(band); | ||
} | ||
this.drawIndicators(); | ||
this.updateImages(); | ||
}; | ||
animator_1.default.registerView(this); | ||
event_bus_1.default.register(constants_1.EventType.ZoomDone, this.onAnimationDone); | ||
event_bus_1.default.register(constants_1.EventType.ScrollDone, this.onAnimationDone); | ||
} | ||
updateImages() { | ||
return tslib_1.__awaiter(this, void 0, void 0, function* () { | ||
for (const band of props_1.default.eventsBands) { | ||
for (const event of band.visibleEvents) { | ||
if (event.img == null) | ||
continue; | ||
if (event.image == null) { | ||
const path = `${props_1.default.imagePath}/${event.wid}__${constants_1.IMAGE_SIZE}.${event.img}`; | ||
event.image = new Image(); | ||
const onImgLoad = this.onImgLoad(event); | ||
event.image.addEventListener('load', onImgLoad); | ||
event.image.addEventListener('error', onImgLoad); | ||
event.image.src = path; | ||
} | ||
else { | ||
this.drawImage(event); | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
drawImage(event) { | ||
if (event.image == null || !event.image.complete || !event.image.naturalWidth) | ||
return; | ||
const x = event.time ? event.left : event.left - (event.image.width / 2) - constants_1.IMAGE_BORDER_SIZE; | ||
const y = event.top - event.image.height; | ||
this.ctx.fillStyle = event.color; | ||
this.ctx.fillRect(x, y - constants_1.IMAGE_BORDER_SIZE * 2, event.image.width + constants_1.IMAGE_BORDER_SIZE * 2, event.image.height + constants_1.IMAGE_BORDER_SIZE * 2); | ||
this.ctx.drawImage(event.image, x + constants_1.IMAGE_BORDER_SIZE, y - constants_1.IMAGE_BORDER_SIZE, event.image.width, event.image.height); | ||
} | ||
render() { | ||
@@ -63,4 +118,25 @@ this.canvas = create_element_1.default('canvas', 'main', [ | ||
else { | ||
let left = event.left; | ||
let width = event.width; | ||
if (event.uncertain_from_width > 1) { | ||
const gradient = this.ctx.createLinearGradient(event.left, 0, event.left + event.uncertain_from_width, 0); | ||
gradient.addColorStop(0, 'white'); | ||
gradient.addColorStop(1, event.color); | ||
this.ctx.fillStyle = gradient; | ||
this.ctx.fillRect(event.left, event.top, event.uncertain_from_width, constants_1.EVENT_HEIGHT); | ||
left = event.left + event.uncertain_from_width; | ||
width -= event.uncertain_from_width; | ||
} | ||
if (event.uncertain_to_width > 1) { | ||
width -= event.uncertain_to_width; | ||
const gradientLeft = left + width; | ||
const gradientWidth = gradientLeft + event.uncertain_to_width; | ||
const gradient = this.ctx.createLinearGradient(gradientLeft, 0, gradientWidth, 0); | ||
gradient.addColorStop(0, event.color); | ||
gradient.addColorStop(1, 'white'); | ||
this.ctx.fillStyle = gradient; | ||
this.ctx.fillRect(gradientLeft, event.top, event.uncertain_to_width, constants_1.EVENT_HEIGHT); | ||
} | ||
this.ctx.fillStyle = event.color; | ||
this.ctx.fillRect(event.left, event.top, event.width, constants_1.EVENT_HEIGHT); | ||
this.ctx.fillRect(left, event.top, width, constants_1.EVENT_HEIGHT); | ||
} | ||
@@ -71,16 +147,13 @@ } | ||
drawEventsText(band) { | ||
this.ctx.font = '11px sans-serif'; | ||
this.ctx.font = `${constants_1.FONT_SIZE}px sans-serif`; | ||
this.ctx.fillStyle = `rgb(40, 40, 40)`; | ||
for (const event of band.visibleEvents) { | ||
let eventWidth = event.time === 0 ? event.padding : event.width; | ||
let eventLeft = event.left; | ||
if (event.left < 0 && event.time !== 0) { | ||
eventWidth = event.width + event.left; | ||
eventLeft = 0; | ||
eventLeft = -event.uncertain_from_width; | ||
} | ||
let eventLabelLength = event.label.length * constants_1.PIXELS_PER_LETTER; | ||
if (eventLabelLength <= eventWidth) { | ||
const paddingLeft = event.time ? 3 : 8; | ||
this.ctx.fillText(event.label, eventLeft + paddingLeft, event.top + constants_1.EVENT_HEIGHT - 3); | ||
} | ||
const paddingLeft = event.time ? constants_1.FONT_SIZE / 3 : constants_1.FONT_SIZE / 1.2; | ||
const x = eventLeft + paddingLeft + event.uncertain_from_width; | ||
const y = event.top + constants_1.FONT_SIZE + ((constants_1.EVENT_HEIGHT - constants_1.FONT_SIZE) / 2) - 2; | ||
this.ctx.fillText(event.lbl, Math.round(x), Math.round(y)); | ||
} | ||
@@ -109,3 +182,3 @@ } | ||
this.indicatorsCtx.rect(rightIndicatorLeftX, indicatorTOP, props_1.default.viewportWidth, band.visibleHeight); | ||
this.indicatorsCtx.rect(leftIndicatorRightX, indicatorTOP + band.visibleHeight - constants_1.DATE_BAR_HEIGHT, rightIndicatorLeftX - leftIndicatorRightX, constants_1.DATE_BAR_HEIGHT); | ||
this.indicatorsCtx.rect(leftIndicatorRightX, indicatorTOP + band.availableHeight, rightIndicatorLeftX - leftIndicatorRightX, band.visibleHeight - band.availableHeight); | ||
} | ||
@@ -112,0 +185,0 @@ this.indicatorsCtx.fillStyle = `rgba(0, 0, 0, .04)`; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const props_1 = require("../../models/props"); | ||
const constants_1 = require("../../constants"); | ||
const dates_1 = require("../../utils/dates"); | ||
const smallFont = "11px sans-serif"; | ||
const bigFont = "13px sans-serif"; | ||
function isSpecialRuler(date, band) { | ||
@@ -39,3 +38,3 @@ if (band.granularity === "CENTURY" && new Date(date).getUTCFullYear() % 1000 === 0) | ||
ctx.beginPath(); | ||
ctx.font = smallFont; | ||
ctx.font = `${constants_1.FONT_SIZE}px sans-serif`; | ||
ctx.fillStyle = `rgb(205, 205, 205)`; | ||
@@ -48,3 +47,3 @@ for (const date of normalRulerDates) { | ||
ctx.beginPath(); | ||
ctx.font = bigFont; | ||
ctx.font = `${constants_1.FONT_SIZE * 1.2}px sans-serif`; | ||
ctx.fillStyle = `rgb(120, 120, 120)`; | ||
@@ -51,0 +50,0 @@ for (const date of specialRulerDates) { |
@@ -1,1 +0,16 @@ | ||
!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(s){if(e[s])return e[s].exports;var n=e[s]={i:s,l:!1,exports:{}};return t[s].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=t,i.c=e,i.d=function(t,e,s){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:s})},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 s=Object.create(null);if(i.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)i.d(s,n,function(e){return t[e]}.bind(null,n));return s},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="/dist/",i(i.s=11)}([function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=i(1),n=i(3),o=i(2);function r(t){return t.type===o.BandType.EventsBand}function a(t){return t.type===o.BandType.MinimapBand}class l{constructor(){this.defaultCenterRatio=.5,this.centerChangeDone=n.debounce(()=>{document.dispatchEvent(new CustomEvent(s.CENTER_CHANGE_DONE))},300)}get center(){return this._center}set center(t){this._center===this.from&&t<this.from||this._center===this.to&&t>this.to||(t<this.from?this._center=this.from:t>this.to?this._center=this.to:this._center=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)}init(t){null==t.rootElement&&console.error("[init] No rootElement found"),this.rootElement=t.rootElement,this.dimensions=this.rootElement;const[e,i]=t.bands.reduce((t,e)=>{if(e.type===o.BandType.MinimapBand)return t;const i=e,s=null==i.config.orderedEvents?i.config.events:i.config.orderedEvents.events;return t[0].push(s[0].date_min||s[0].date),t[1].push(s.reduce((t,e)=>Math.max(t,e.end_date||-1/0,e.end_date_max||-1/0),-1/0)),t},[[],[]]);this.from=Math.min(...e),this.to=Math.max(...i),this.time=this.to-this.from,this.center=null!=t.center?t.center:this.from+this.defaultCenterRatio*this.time,this.bands=t.bands,this.eventsBands=this.bands.filter(r),this.minimapBands=this.bands.filter(a),this.controlBand=null!=t.controlBand?t.controlBand:this.eventsBands[0];for(const t of this.bands)t.init()}resize(){this.dimensions=this.rootElement}}e.Props=l,e.default=new l},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.EVENT_HEIGHT=14,e.EVENT_ROW_HEIGHT=16,e.DATE_BAR_HEIGHT=e.EVENT_ROW_HEIGHT,e.RULER_LABELS_HEIGHT=60,e.CENTER_CHANGE_DONE="CENTER_CHANGE_DONE",e.ZOOM_DONE="ZOOM_DONE",e.SCROLL_DONE="SCROLL_DONE",e.PIXELS_PER_LETTER=8;e.RawSegment=class{},e.colors=["rgba(211,84,0","rgba(219,10,91","rgba(31,58,147","rgba(0,128,0"].map(t=>(e=1)=>`${t},${e})`)},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=i(6),n=i(0),o=i(1),r=i(3),a=i(4);!function(t){t[t.EventsBand=0]="EventsBand",t[t.MinimapBand=1]="MinimapBand"}(e.BandType||(e.BandType={}));e.default=class{constructor(t){this.config=t,this.defaultZoomLevel=0}get offsetX(){return this._offsetX}set offsetX(t){this.prevOffsetX=this.offsetX||t,this._offsetX=t}get zoomLevel(){return this._zoomLevel}set zoomLevel(t){t<0&&(t=0),this.visibleRatio=r.visibleRatio(t),this.width=Math.round(n.default.viewportWidth/this.visibleRatio),this.pixelsPerMillisecond=this.width/n.default.time,this.time=this.visibleRatio*n.default.time,this.granularity=s.getGranularity(this.pixelsPerMillisecond),this.nextDate=s.subsequentDate(this.granularity),this.prevZoomLevel=this.zoomLevel||t,this._zoomLevel=t,this.setHorizontalProps()}setVerticalProps(){this.visibleHeight=Math.round(this.config.heightRatio*n.default.viewportHeight),this.availableHeight=this.visibleHeight-o.DATE_BAR_HEIGHT,this.visibleRowsCount=Math.floor(this.availableHeight/o.EVENT_ROW_HEIGHT)-1,this.top=Math.round(this.config.topOffsetRatio*n.default.viewportHeight)}setHorizontalProps(){this.from=n.default.center-this.time/2,this.to=n.default.center+this.time/2,this.offsetX=(n.default.from-this.from)*this.pixelsPerMillisecond}init(){this.zoomLevel=this.config.zoomLevel,this.setVerticalProps(),a.default.registerModel(this)}resize(){this.zoomLevel=this.zoomLevel,this.setVerticalProps()}update(){this.setHorizontalProps()}updateConfig(t){Object.keys(t).forEach(e=>{this.config.hasOwnProperty(e)&&(this.config[e]=t[e])})}positionAtTimestamp(t){return Math.round((t-this.from)*this.pixelsPerMillisecond)}timestampAtProportion(t){return n.default.from+n.default.time*t}timestampAtPosition(t){return this.from+t/this.pixelsPerMillisecond}}},function(t,e,i){"use strict";function s(t){return Math.pow(2,-1*t)}function n(t){if(null==t)return null;const e=new Date(t);return`${e.getFullYear()}-${e.getMonth()+1}-${e.getDate()}`}Object.defineProperty(e,"__esModule",{value:!0}),e.debounce=((t,e)=>{let i;return()=>{clearTimeout(i),i=setTimeout(t,e)}}),e.visibleRatio=s,e.createRange=function(t){return Array.apply(null,{length:t}).map(Number.call,Number)},e.selectRandom=function(t,e){const i=[];for(;i.length<e;){const s=t[Math.floor(Math.random()*t.length)];(-1===i.indexOf(s)||t.length<e)&&i.push(s)}return i},e.calcPixelsPerMillisecond=function(t,e,i){return t/s(e)/i},e.logEvent=function(t,...e){console.log(t.label,t,t.left,n(t.from),n(t.to),e)}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=i(0),n=i(1);var o;!function(t){t[t.Backward=-1]="Backward",t[t.Stop=0]="Stop",t[t.Forward=1]="Forward"}(o||(o={}));class r{constructor(){this.elapsedTimeThreshold=2e3,this.goToDuration=300,this.zoomToDuration=300,this.multipliers=[.25,.5,1,2,4,8,16],this.multiplier=1,this.direction=o.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.default.center+=s.default.controlBand.time/480*this.multiplier*this.direction;else if(null!=this.centerMarker){const t=this.goToDuration-this.elapsedTimeTotal,i=Math.abs(this.centerMarker-s.default.center)/(t/e);t<e?(s.default.center=this.centerMarker,this.stop()):s.default.center=s.default.center+i*this.direction}else if(null!=this.zoomMarker){const t=this.zoomToDuration-this.elapsedTimeTotal,i=(this.zoomMarker-this.activeBand.zoomLevel)/(t/e);if(t<e)this.activeBand.zoomLevel=this.zoomMarker,s.default.eventsBands.forEach(t=>{t===this.activeBand?this.activeBand.zoomLevel=this.zoomMarker:t.zoomLevel=this.zoomMarker+(t.config.zoomLevel-this.activeBand.config.zoomLevel)}),this.adjustMinimapBands(),document.dispatchEvent(new CustomEvent(n.ZOOM_DONE)),this.stop();else{for(const t of s.default.eventsBands)t.zoomLevel=t.zoomLevel+i;this.adjustMinimapBands()}}this.models.forEach(t=>t.update()),this.views.forEach(t=>t.update())}this.elapsedTimeTotal+=e,this.elapsedTimeTotal>this.elapsedTimeThreshold&&this.resetElapsedTimeTotal(),(this.isPlaying()||null!=this.zoomMarker)&&(s.default.center>=s.default.from&&s.default.center<=s.default.to||null!=this.centerMarker||null!=this.zoomMarker?(this.prevTimestamp=t,requestAnimationFrame(this.animate)):this.stop())})}registerModel(t){this.models.push(t)}registerView(t){this.views.push(t)}adjustMinimapBands(){s.default.minimapBands.forEach(t=>{this.activeBand.zoomLevel<t.config.zoomLevel&&(t.zoomLevel=this.activeBand.zoomLevel)})}resetElapsedTimeTotal(){this.elapsedTimeTotal=0,document.dispatchEvent(new CustomEvent(n.CENTER_CHANGE_DONE))}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.default.center?this.playForward():this.playBackward()}zoomTo(t,e){null==this.zoomMarker&&(e<0&&(e=0),t!==this.activeBand&&(this.stop(),this.activeBand=t),this.activeBand.zoomLevel!==e&&(this.zoomMarker=e,this.nextFrame()))}speed(t){const e=parseFloat(t);-1!==this.multipliers.indexOf(e)&&(this.multiplier=e)}isPlaying(){return this.direction!==o.Stop}isPlayingForward(){return this.direction===o.Forward}isPlayingBackward(){return this.direction===o.Backward}nextFrame(){requestAnimationFrame(this.animate)}playForward(){this.direction=o.Forward,this.nextFrame()}playBackward(){this.direction=o.Backward,this.nextFrame()}stop(){this.direction=o.Stop,this.activeBand=null,this.centerMarker=null,this.zoomMarker=null,this.prevTimestamp=null,this.elapsedTimeTotal=0}toggle(){this.isPlaying()?this.stop():this.nextFrame()}}e.Animator=r,e.default=new r},function(t,e,i){"use strict";let s;if(Object.defineProperty(e,"__esModule",{value:!0}),e.createSvg=((t,e,i={})=>{const s=document.createElementNS("http://www.w3.org/2000/svg",t);return null!=e&&s.setAttribute("style",e.join(";").concat(";")),Object.keys(i).forEach(t=>s.setAttribute(t,i[t])),s}),"undefined"!=typeof window){const t=document.createElement("style");document.head.appendChild(t),s=t.sheet}const n={};e.default=function(t,e,i,o){if(!e)return document.createElement(t);let r;return n.hasOwnProperty(e)?r=n[e].cloneNode(!1):((r=document.createElement(t)).classList.add(e),i&&s.insertRule(`.${e} { ${i.join(";").concat(";")} }`),n[e]=r.cloneNode(!1)),o&&r.setAttribute("style",o.join(";").concat(";")),r}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],n=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function o(t){return n[t.getUTCMonth()]}function r(t){const e=t.getUTCDate();return`${s[t.getUTCDay()]}, ${e}${function(t){return["st","nd","rd"][((t+90)%100-10)%10-1]||"th"}(e)}`}function a(t){return t.getUTCHours().toString().padStart(2,"0")}function l(t){return t.getUTCMinutes().toString().padStart(2,"0")}function h(t){return t.getUTCSeconds().toString().padStart(2,"0")}function d(t){return t.getUTCMilliseconds().toString().padStart(3,"0")}function u(t){return"YEAR"===t||"YEAR_5"===t||"DECADE"===t||"DECADE_5"===t||"CENTURY"===t||"CENTURY_5"===t||"MILLENIUM"===t}e.formatDate=((t,e)=>{if(null==t)return"∞";const i=new Date(t);let s=i.getUTCFullYear().toString();return u(e)?s:(s=`${o(i)} ${s}`,"MONHT"===e?s:(s=`${r(i)} ${s}`,"DAY"===e?s:(s=`${s} at ${a(i)}:`,"HOUR"===e?`${s}00`:(s=`${s}${l(i)}`,"MINUTE"===e?s:(s=`${s}:${h(i)}`,"SECOND"===e?s:`${s}.${d(i)}`)))))}),e.getGranularity=(t=>t>58?"MILLISECOND":t>12?"MILLISECOND_10":t>2.3?"MILLISECOND_50":t>1.5?"MILLISECOND_100":t>.4?"MILLISECOND_500":t>.00112?"SECOND":t>112e-6?"MINUTE":t>112e-7?"HOUR":t>8e-7?"DAY":t>2.6e-7?"WEEK":t>2.2e-8?"MONHT":t>2.2e-9?"YEAR":t>3.3e-10?"YEAR_5":t>1.6e-10?"DECADE":t>8e-11?"DECADE_5":t>1e-11?"CENTURY":t>5e-12?"CENTURY_5":"MILLENIUM"),e.getStep=(t=>{if("YEAR"===t)return 1;if("YEAR_5"===t)return 5;if("DECADE"===t)return 10;if("DECADE_5"===t)return 50;if("CENTURY"===t)return 100;if("CENTURY_5"===t)return 500;if("MILLENIUM"===t)return 1e3;if("MILLISECOND"===t)return 1;if("MILLISECOND_10"===t)return 10;if("MILLISECOND_50"===t)return 50;if("MILLISECOND_100"===t)return 100;if("MILLISECOND_500"===t)return 500;throw new RangeError("[getStep] Only steps with a granularity greater than 'year' calculated")}),e.subsequentDate=function(t){return u(t)?i=>{let s=new Date(i),n=s.getUTCFullYear()+1;if("YEAR"!==t){const i=e.getStep(t);for(;n%i!=0;)n+=1}return n>-1&&n<100?(s.setUTCFullYear(n),s.getTime()):Date.UTC(n,0,1)}:"MONHT"===t?t=>{const e=new Date(t);return Date.UTC(e.getUTCFullYear(),e.getUTCMonth()+1,1)}:"WEEK"===t?t=>{const e=new Date(t);return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()+7)}:"DAY"===t?t=>{const e=new Date(t);return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()+1)}:"HOUR"===t?t=>{const e=new Date(t);return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours()+1)}:"MINUTE"===t?t=>{const e=new Date(t);return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes()+1)}:"SECOND"===t?t=>{const e=new Date(t);return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds()+1)}:"MILLISECOND"===t.slice(0,"MILLISECOND".length)?i=>{const s=e.getStep(t),n=new Date(i);let o=n.getUTCMilliseconds()+1;return s>1&&(o=o+s-o%s),Date.UTC(n.getUTCFullYear(),n.getUTCMonth(),n.getUTCDate(),n.getUTCHours(),n.getUTCMinutes(),n.getUTCSeconds(),o)}:void 0},e.byDate=function(t,e){const i=null!=t.date_min?t.date_min:t.date,s=null!=e.date_min?e.date_min:e.date;if(i<s)return-1;if(i>s)return 1;const n=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 n<o?-1:n>o?1:0};e.labelBody=((t,e)=>{const i=new Date(t);return u(e)?i.getUTCFullYear().toString():"MONHT"===e?o(i):"WEEK"===e?`${o(i)}, 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 s=new Date(Date.UTC(e.getUTCFullYear(),0,1));return Math.ceil(((e.getTime()-s.getTime())/864e5+1)/7)})(i)}`:"DAY"===e?`${r(i)} ${o(i)}`:"HOUR"===e?`${a(i)}:00`:"MINUTE"===e?`${a(i)}:${l(i)}`:"SECOND"===e?`${a(i)}:${l(i)}:${h(i)}`:"MILLISECOND"===e.slice(0,"MILLISECOND".length)?`${a(i)}:${l(i)}:${h(i)}.${d(i)}`:void 0})},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});e.DomainConfig=class{};class s{constructor(){this.heightRatio=1,this.rulers=!0,this.rulerLabels=!0,this.topOffsetRatio=0,this.zoomLevel=0}}e.BandConfig=s;e.MinimapBandConfig=class extends s{constructor(){super(...arguments),this.indicatorFor=0,this.targets=[]}};e.EventsBandConfig=class extends s{};e.default=class{}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=i(2),n=i(0),o=i(5),r=i(9),a=i(4),l=i(1);e.default=class{constructor(t){this.band=t,this.onMouseDown=(t=>{document.addEventListener("mouseup",this.onMouseUp),this.dragStartTime=Date.now(),this.dragStartPosition=[t.clientX,t.clientY],this.dragOffsetX=t.clientX,this.dragOffsetY=t.clientY}),this.onMouseMove=(t=>{if(null==this.dragOffsetX)return;const e=t.clientY-this.dragOffsetY,i=t.clientX-this.dragOffsetX;if(this.band.type===s.BandType.EventsBand){const t=this.band;(0!==t.offsetY||Math.abs(e)>Math.abs(i)&&Math.abs(e)>5)&&(t.offsetY=e)}const o=i/this.band.pixelsPerMillisecond;n.default.center-=o,a.default.nextFrame(),this.dragOffsetX=t.clientX,this.dragOffsetY=t.clientY}),this.onMouseUp=(t=>{this.lastDragInterval=Date.now()-this.dragStartTime,this.dispatchScrollDoneEvent(t),this.dragOffsetX=null,this.dragOffsetY=null,document.removeEventListener("mouseup",this.onMouseUp)}),this.onDblClick=(t=>{const e=this.band.timestampAtPosition(t.clientX);a.default.goTo(e)})}render(){return this.rootElement=o.default("div","band-wrap",["position: absolute","z-index: 2"],[`height: ${this.band.visibleHeight}px`,`top: ${this.band.top}px`,`width: ${n.default.viewportWidth}px`]),r.default.register("mousedown",this.onMouseDown,this.rootElement),r.default.register("mousemove",this.onMouseMove,this.rootElement),r.default.register("dblclick",this.onDblClick,this.rootElement),this.rootElement}dispatchScrollDoneEvent(t){const e=[this.dragStartPosition[0]-t.clientX,this.dragStartPosition[1]-t.clientY].map(Math.abs).some(t=>t>5);(this.lastDragInterval>200||e)&&document.dispatchEvent(new CustomEvent(l.SCROLL_DONE))}resize(){this.rootElement.style.cssText=`height: ${this.band.visibleHeight}px; top: ${this.band.top}px; width: ${n.default.viewportWidth}px;`}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});class s{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,s]=t;s.removeEventListener(e,i)}),this.eventsListeners=[]}}e.EventBus=s,e.default=new s},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=i(1);class n{constructor(){this.events=[],this.row_count=0}}e.OrderedEvents=n;const o=8;e.orderEvents=function(t,e){if(!t.length)return new n;let i=0;const r=[],a=2*s.EVENT_HEIGHT/e;return{events:t=t.map(t=>{let s;null==t.label&&(t.label="NO LABEL"),t.from=t.date_min||t.date,t.to=t.end_date_max||t.end_date,null==t.to&&(t.to=t.from),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+a);let n=0;for(;null==s&&n<r.length;){let e=0,i=!0;for(;i&&e<r[n].length&&!(t.to<r[n][e][0]);)i=t.from>r[n][e][1],e++;i&&(r[n].push([t.from,t.from+t.time+t.space]),s=n),n++}return null==s&&(s=r.push([[t.from,t.from+t.time+t.space]])-1),s>i&&(i=s),t.row=s,t}),row_count:r.length}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=i(0);e.TimelineProps=s.Props;const n=i(7);e.TimelineConfig=n.default;const o=i(8),r=i(5),a=i(3);e.calcPixelsPerMillisecond=a.calcPixelsPerMillisecond;const l=i(10);e.OrderedEvents=l.OrderedEvents,e.orderEvents=l.orderEvents;const h=i(12),d=i(13),u=i(14),c=i(16),f=i(17);e.MinimapBand=f.default;const p=i(18);e.EventsBand=p.default;const m=i(6);e.formatDate=m.formatDate;const v=i(19);e.RawEv3nt=v.RawEv3nt;const g=i(2);e.default=class extends h.default{constructor(t,e,i){super(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))}),s.default.init(t),t.rootElement.appendChild(this.render());const n=a.debounce(this.resize,600);window.addEventListener("resize",n)}render(){this.wrapper=r.default("div","wrapper",["box-sizing: border-box","height: 100%","overflow: hidden","position: relative","user-select: none","width: 100%"]),this.views=s.default.bands.map(t=>t.type===g.BandType.EventsBand?new d.default(t,this.onSelect):new o.default(t)),this.views.push(new u.default),this.views.forEach(this.appendToWrapper),this.renderLabels();const t=r.default("div","red-line",["background-color: rgb(126, 0, 0)","bottom: 0","left: calc(50% - 1px)","position: absolute","top: 0","width: 2px","z-index: 4"]);return this.wrapper.appendChild(t),this.wrapper}renderLabels(){s.default.bands.filter(t=>t.type===g.BandType.EventsBand&&null!=t.config.label).map(t=>new c.default(t)).forEach(this.appendToWrapper)}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=i(4),n=i(1),o=i(0);e.default=class{constructor(t){this.onChange=t,this.animator=s.default,this.handleChange=(()=>{this.onChange(o.default)}),this.resize=(()=>{o.default.resize();for(const t of o.default.bands)t.resize();for(const t of this.views)t.resize();this.animator.nextFrame()}),document.addEventListener("keydown",t=>{189===t.keyCode&&o.default.controlBand.zoomOut(),187===t.keyCode&&o.default.controlBand.zoomIn()}),null!=this.onChange&&"function"==typeof this.onChange&&(document.addEventListener(n.CENTER_CHANGE_DONE,this.handleChange),document.addEventListener(n.ZOOM_DONE,this.handleChange))}reload(){this.resize()}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=i(8),n=i(9),o=i(3);e.default=class extends s.default{constructor(t,e){super(t),this.band=t,this.select=e,this.onWheel=(t=>{0===Math.abs(t.deltaX)&&0!==t.deltaY&&(t.deltaY<0&&this.zoomOut(),t.deltaY>0&&this.zoomIn())}),this.onClick=(t=>{if(this.lastDragInterval>175)return;const e=this.band.getEventByCoordinates(t.clientX,t.clientY);e&&this.select&&(this.select(e),o.logEvent(e))})}render(){const t=super.render();return n.default.register("click",this.onClick,this.rootElement),n.default.register("wheel",this.onWheel,this.rootElement),t}zoomIn(){this.band.zoomIn()}zoomOut(){this.band.zoomOut()}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=i(5),n=i(0),o=i(1),r=i(4),a=i(15),l=i(2);e.default=class{constructor(){this.indicatorsDrawn=!1,this.update=(()=>{n.default.bands.forEach(t=>{t.type===l.BandType.EventsBand?this.drawEventsBand(t):this.drawMinimapBand(t)}),this.drawIndicators()}),r.default.registerView(this)}render(){return this.canvas=s.default("canvas","main",["position: absolute"]),this.canvas.width=n.default.viewportWidth,this.canvas.height=n.default.viewportHeight,this.ctx=this.canvas.getContext("2d"),this.indicatorsCanvas=s.default("canvas","indicators",["position: absolute"],["z-index: 1"]),this.indicatorsCanvas.width=n.default.viewportWidth,this.indicatorsCanvas.height=n.default.viewportHeight,this.indicatorsCtx=this.indicatorsCanvas.getContext("2d"),this.update(),[this.canvas,this.indicatorsCanvas]}resize(){this.indicatorsCanvas.width=n.default.viewportWidth,this.indicatorsCanvas.height=n.default.viewportHeight,this.canvas.width=n.default.viewportWidth,this.canvas.height=n.default.viewportHeight,this.indicatorsDrawn=!1}clear(t){this.ctx.clearRect(0,t.top,this.canvas.width,t.visibleHeight)}drawEventsBand(t){this.clear(t),a.default(this.ctx,t);for(const e of t.visibleEvents)e.time?(this.ctx.fillStyle=e.color,this.ctx.fillRect(e.left,e.top,e.width,o.EVENT_HEIGHT)):(this.ctx.moveTo(e.left,e.top+o.EVENT_HEIGHT/2),this.ctx.beginPath(),this.ctx.arc(e.left,e.top+o.EVENT_HEIGHT/2,o.EVENT_HEIGHT/3,0,2*Math.PI),this.ctx.fillStyle=e.color,this.ctx.fill());this.drawEventsText(t)}drawEventsText(t){this.ctx.font="11px sans-serif",this.ctx.fillStyle="rgb(40, 40, 40)";for(const e of t.visibleEvents){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*o.PIXELS_PER_LETTER<=t){const t=e.time?3:8;this.ctx.fillText(e.label,i+t,e.top+o.EVENT_HEIGHT-3)}}}drawMinimapBand(t){if(t.isDrawn&&t.prevOffsetX===t.offsetX&&t.prevZoomLevel===t.zoomLevel)return;this.clear(t),a.default(this.ctx,t);const e=t.draw();this.ctx.drawImage(e,0,t.top,n.default.viewportWidth,t.availableHeight),t.isDrawn=!0}drawIndicators(){if(!this.indicatorsDrawn||!n.default.eventsBands.every(t=>t.prevZoomLevel===t.zoomLevel)){this.indicatorsCtx.clearRect(0,0,n.default.viewportWidth,n.default.viewportHeight),this.indicatorsCtx.beginPath();for(const t of n.default.minimapBands){const e=n.default.eventsBands[t.config.indicatorFor],i=Math.round(t.config.topOffsetRatio*n.default.viewportHeight),s=t.positionAtTimestamp(e.from);this.indicatorsCtx.rect(0,i,s,t.visibleHeight);const r=t.positionAtTimestamp(e.to);this.indicatorsCtx.rect(r,i,n.default.viewportWidth,t.visibleHeight),this.indicatorsCtx.rect(s,i+t.visibleHeight-o.DATE_BAR_HEIGHT,r-s,o.DATE_BAR_HEIGHT)}this.indicatorsCtx.fillStyle="rgba(0, 0, 0, .04)",this.indicatorsCtx.fill(),this.indicatorsCtx.closePath(),this.indicatorsDrawn=!0}}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=i(0),n=i(6),o="11px sans-serif",r="13px sans-serif";function a(t,e){return"CENTURY"===e.granularity&&new Date(t).getUTCFullYear()%1e3==0||("YEAR_5"===e.granularity&&new Date(t).getUTCFullYear()%50==0||"YEAR"===e.granularity&&new Date(t).getUTCFullYear()%5==0)}function l(t,e,i,s,o){const r=e.positionAtTimestamp(i);t.moveTo(r,s),t.lineTo(r,o),e.config.rulerLabels&&t.fillText(n.labelBody(i,e.granularity),r+3,o-3)}e.default=function(t,e){if(!e.config.rulers)return;let i=e.nextDate(e.from);const n=e.config.topOffsetRatio*s.default.viewportHeight,h=e.config.heightRatio*s.default.viewportHeight,d=[],u=[];for(;i<e.to;)a(i,e)?u.push(i):d.push(i),i=e.nextDate(i);t.beginPath(),t.font=o,t.fillStyle="rgb(205, 205, 205)";for(const i of d)l(t,e,i,n,n+h);t.strokeStyle="rgb(235, 235, 235)",t.stroke(),t.beginPath(),t.font=r,t.fillStyle="rgb(120, 120, 120)";for(const i of u)l(t,e,i,n,n+h);t.strokeStyle="rgb(150, 150, 150)",t.stroke()}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=i(5);e.default=class{constructor(t){this.band=t}render(){const t=s.default("div","events-label-wrapper",["border-top: 1px solid #CCC","pointer-events: none","position: absolute","width: 100%","z-index: 3"],[`top: ${100*this.band.config.topOffsetRatio}%`]),e=s.default("div","events-label",["background: white","border-bottom-right-radius: 4px","box-shadow: 1px 2px 4px #AAA","color: #444","display: inline-block","font-family: sans-serif","font-size: .8em","padding: 4px 8px"]);return e.innerText=this.band.config.label,t.appendChild(e),t}resize(){}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=i(2),n=i(7),o=i(0),r=i(5);e.default=class extends s.default{constructor(t){super(function(t){const e=Object.assign({},new n.MinimapBandConfig,t);return e.targets.length||e.targets.push(0),e}(t)),this.type=s.BandType.MinimapBand,this.canvas=r.default("canvas"),this.ctx=this.canvas.getContext("2d"),this.nextCanvas=r.default("canvas"),this.nextCtx=this.nextCanvas.getContext("2d"),this.isDrawn=!1}init(){super.init(),this.maxRowCount=this.config.targets.reduce((t,e)=>{const{rowCount:i}=o.default.eventsBands[e];return Math.max(t,i)},0);const t=this.availableHeight/this.maxRowCount;this.eventHeight=t<1?1:Math.floor(t),this.canvas.width=o.default.viewportWidth,this.canvas.height=this.maxRowCount*this.eventHeight,this.nextCanvas.width=this.canvas.width,this.nextCanvas.height=this.canvas.height}resize(){super.resize(),this.isDrawn=!1}draw(){return this.isDrawn?this.updateNextCanvas():this.drawEvents(),this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.drawImage(this.nextCanvas,0,0),this.canvas}drawEvents(t=this.from,e=this.to){this.nextCtx.beginPath(),this.config.targets.forEach(i=>{const s=o.default.eventsBands[i];for(const i of s.events){if(i.from>e||i.to<t)continue;const s=Math.round(i.time*this.pixelsPerMillisecond),n=this.positionAtTimestamp(null!=i.date_min?i.date_min:i.date),o=this.maxRowCount-(i.row+1)*this.eventHeight,r=s<1?1:s;this.nextCtx.rect(n,o,r,this.eventHeight)}}),this.nextCtx.fillStyle="rgb(190, 190, 190)",this.nextCtx.fill()}updateNextCanvas(){const t=Math.round(this.offsetX-this.prevOffsetX);if(0===t)return this.canvas;let e,i;this.nextCtx.clearRect(0,0,this.nextCanvas.width,this.nextCanvas.height),this.nextCtx.drawImage(this.canvas,t,0),t<0?(e=this.timestampAtPosition(o.default.viewportWidth+t),i=this.to):(e=this.from,i=this.timestampAtPosition(t)),this.drawEvents(e,i)}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const s=i(2),n=i(7),o=i(4),r=i(1),a=i(0),l=i(10),h=i(6),d=i(3);e.default=class extends s.default{constructor(t){super(Object.assign({},new n.EventsBandConfig,t)),this.type=s.BandType.EventsBand,this.events=[],this.rowCount=0,this.visibleEvents=[],this._offsetY=0,null!=this.config.events&&this.config.events.sort(h.byDate)}get offsetY(){return this._offsetY}set offsetY(t){this._offsetY+=t,this._offsetY<0&&(this._offsetY=0);const e=this.height>this.availableHeight?this.height-this.availableHeight+r.EVENT_ROW_HEIGHT:0;this._offsetY>e&&(this._offsetY=e);const i=this._offsetY/r.EVENT_ROW_HEIGHT;this.lowestVisibleRow=Math.ceil(i),this.highestVisibleRow=this.lowestVisibleRow+this.visibleRowsCount}init(){super.init();const t=d.calcPixelsPerMillisecond(a.default.viewportWidth,this.config.zoomLevel||0,a.default.time),e=null==this.config.orderedEvents?l.orderEvents(this.config.events,t):this.config.orderedEvents;this.events=e.events,this.rowCount=e.row_count,this.height=r.EVENT_ROW_HEIGHT*this.rowCount,this.offsetY=0,this.updateEvents()}getColor(t,e){const i=[49,220,215];let s;if(a.default.center>e)s=a.default.center-e;else{if(!(a.default.center<t))return`rgb(${i.join(", ")})`;s=t-a.default.center}const n=s/(this.time/2),o=a.default.center>e?[253,231,37]:[204,104,232];return`rgb(${i.map((t,e)=>t+(o[e]-t)*n).join(", ")})`}updateEvents(){this.visibleEvents=this.events.filter(t=>!(t.from>this.to||t.to<this.from)&&t.row>=this.lowestVisibleRow&&t.row<=this.highestVisibleRow).map(t=>(t.left=this.positionAtTimestamp(t.from),t.width=Math.round(t.time*this.pixelsPerMillisecond),t.time&&t.width<1&&(t.width=1),t.padding=Math.round(t.space*this.pixelsPerMillisecond),t.top=this.top+this.availableHeight-(t.row+1)*r.EVENT_ROW_HEIGHT+this.offsetY,t.color=this.getColor(t.from,t.to),t))}update(){super.update(),this.updateEvents()}getEventByCoordinates(t,e){const i=this.timestampAtPosition(t),s=a.default.viewportOffset+this.top+this.availableHeight+this.offsetY,n=Math.floor((s-e)/r.EVENT_ROW_HEIGHT);return this.events.find(t=>!(!(t.from<i&&t.from+t.time+t.space>i)||t.row<this.lowestVisibleRow||t.row>this.highestVisibleRow)&&t.row===n)}zoomIn(){o.default.zoomTo(this,this.zoomLevel+1)}zoomOut(){o.default.zoomTo(this,this.zoomLevel-1)}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});e.RawEv3nt=class{constructor(){this.date_granularity="DAY"}}}])}); | ||
!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="/dist/",i(i.s=9)}([function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.IMAGE_SIZES=[16,32,64,128,256],e.EVENT_HEIGHT=16,e.LETTER_WIDTH=Math.round(.1875*e.EVENT_HEIGHT+3.5),e.FONT_SIZE=Math.round(.3125*e.EVENT_HEIGHT+6),e.ROW_SPACING=Math.round(e.EVENT_HEIGHT/3),e.EVENT_ROW_HEIGHT=e.EVENT_HEIGHT+e.ROW_SPACING,e.DATE_BAR_HEIGHT=e.EVENT_ROW_HEIGHT,e.IMAGE_BOUNDING_BOX=2*e.EVENT_ROW_HEIGHT-2*e.ROW_SPACING,e.IMAGE_BORDER_SIZE=Math.round(e.ROW_SPACING/2),e.IMAGE_SIZE=e.IMAGE_SIZES.reduce((t,i)=>Math.abs(i-e.IMAGE_BOUNDING_BOX)<Math.abs(t-e.IMAGE_BOUNDING_BOX)?i:t),function(t){t.CenterChange="CenterChange",t.ZoomDone="ZoomDone",t.ScrollDone="ScrollDone",t.Pause="Pause",t.Play="Play",t.Select="Select"}(e.EventType||(e.EventType={})),e.PIXELS_PER_LETTER=8,e.DEFAULT_IMAGE_PATH="/images";e.RawSegment=class{},e.colors=["rgba(211,84,0","rgba(219,10,91","rgba(31,58,147","rgba(0,128,0"].map(t=>(e=1)=>`${t},${e})`)},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(0),s=i(4),o=i(9),r=i(6);function a(t){return t.type===s.BandType.EventsBand}function l(t){return t.type===s.BandType.MinimapBand}class h{constructor(){this.defaultCenterRatio=.5}get center(){return this._center}set center(t){this._center===this.from&&t<this.from||this._center===this.to&&t>this.to||(t<this.from?this._center=this.from:t>this.to?this._center=this.to:this._center=t,r.default.dispatch(n.EventType.CenterChange))}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)}init(t){null==t.rootElement&&console.error("[init] No rootElement found"),this.imagePath=null!=t.imagePath?t.imagePath:n.DEFAULT_IMAGE_PATH,this.rootElement=t.rootElement,this.dimensions=this.rootElement,this.bands=t.bands,this.eventsBands=this.bands.filter(a),this.minimapBands=this.bands.filter(l),this.controlBand=null!=t.controlBand?t.controlBand:this.eventsBands[0];const e=performance.now(),i={bands:this.eventsBands.map(t=>({events:t.config.events,zoomLevel:t.config.zoomLevel})),parent:t.parent,viewportWidth:this.viewportWidth},s=o.orderEvents(i);this.parent=s.parent,this.from=s.from,this.to=s.to,this.time=s.time;const r=performance.now();console.log("Performance: ",`${r-e}ms\n[from] ${new Date(this.from).toUTCString()}\n[ to ] ${new Date(this.to).toUTCString()}`),this.center=null!=t.center?t.center:this.from+this.defaultCenterRatio*this.time;for(const[t,e]of this.eventsBands.entries())e.init(s.bands[t]);for(const t of this.minimapBands)t.init()}resize(){this.dimensions=this.rootElement}}e.Props=h,e.default=new h},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(1),s=i(0),o=i(6);var r;!function(t){t[t.Backward=-1]="Backward",t[t.Stop=0]="Stop",t[t.Forward=1]="Forward"}(r||(r={}));class a{constructor(){this.elapsedTimeThreshold=2e3,this.goToDuration=300,this.zoomToDuration=300,this.multipliers=[.25,.5,1,2,4,8,16],this.multiplier=1,this.direction=r.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)n.default.center+=n.default.controlBand.time/480*this.multiplier*this.direction;else if(null!=this.centerMarker){const t=this.goToDuration-this.elapsedTimeTotal,i=Math.abs(this.centerMarker-n.default.center)/(t/e);t<e?(n.default.center=this.centerMarker,this.stop()):n.default.center=n.default.center+i*this.direction}else if(null!=this.zoomMarker){const t=this.zoomToDuration-this.elapsedTimeTotal,i=(this.zoomMarker-this.activeBand.zoomLevel)/(t/e);if(t<e)this.activeBand.zoomLevel=this.zoomMarker,n.default.eventsBands.forEach(t=>{t===this.activeBand?this.activeBand.zoomLevel=this.zoomMarker:t.zoomLevel=this.zoomMarker+(t.config.zoomLevel-this.activeBand.config.zoomLevel)}),this.adjustMinimapBands(),o.default.dispatch(s.EventType.ZoomDone),this.stop();else{for(const t of n.default.eventsBands)t.zoomLevel=t.zoomLevel+i;this.adjustMinimapBands()}}this.models.forEach(t=>t.update()),this.views.forEach(t=>t.update())}this.elapsedTimeTotal+=e,this.elapsedTimeTotal>this.elapsedTimeThreshold&&this.resetElapsedTimeTotal(),(this.isPlaying()||null!=this.zoomMarker)&&(n.default.center>=n.default.from&&n.default.center<=n.default.to||null!=this.centerMarker||null!=this.zoomMarker?(this.prevTimestamp=t,requestAnimationFrame(this.animate)):this.stop())})}registerModel(t){this.models.push(t)}registerView(t){this.views.push(t)}adjustMinimapBands(){n.default.minimapBands.forEach(t=>{this.activeBand.zoomLevel<t.config.zoomLevel&&(t.zoomLevel=this.activeBand.zoomLevel)})}resetElapsedTimeTotal(){this.elapsedTimeTotal=0,o.default.dispatch(s.EventType.CenterChange)}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>n.default.center?this.playForward():this.playBackward()}zoomTo(t,e){null==this.zoomMarker&&(e<0&&(e=0),t!==this.activeBand&&(this.stop(),this.activeBand=t),this.activeBand.zoomLevel!==e&&(this.zoomMarker=e,this.nextFrame()))}speed(t){const e=parseFloat(t);-1!==this.multipliers.indexOf(e)&&(this.multiplier=e)}isPlaying(){return this.direction!==r.Stop}isPlayingForward(){return this.direction===r.Forward}isPlayingBackward(){return this.direction===r.Backward}nextFrame(){requestAnimationFrame(this.animate)}playForward(){o.default.dispatch(s.EventType.Play),this.direction=r.Forward,this.nextFrame()}playBackward(){o.default.dispatch(s.EventType.Play),this.direction=r.Backward,this.nextFrame()}stop(){o.default.dispatch(s.EventType.Pause),this.direction=r.Stop,this.activeBand=null,this.centerMarker=null,this.zoomMarker=null,this.prevTimestamp=null,this.elapsedTimeTotal=0}toggle(){this.isPlaying()?this.stop():this.nextFrame()}}e.Animator=a,e.default=new a},function(t,e,i){"use strict";let n;if(Object.defineProperty(e,"__esModule",{value:!0}),e.createSvg=((t,e,i={})=>{const n=document.createElementNS("http://www.w3.org/2000/svg",t);return null!=e&&n.setAttribute("style",e.join(";").concat(";")),Object.keys(i).forEach(t=>n.setAttribute(t,i[t])),n}),"undefined"!=typeof window){const t=document.createElement("style");document.head.appendChild(t),n=t.sheet}const s={};e.default=function(t,e,i,o){if(!e)return document.createElement(t);let r;return s.hasOwnProperty(e)?r=s[e].cloneNode(!1):((r=document.createElement(t)).classList.add(e),i&&n.insertRule(`.${e} { ${i.join(";").concat(";")} }`),s[e]=r.cloneNode(!1)),o&&r.setAttribute("style",o.join(";").concat(";")),r}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(5),s=i(1),o=i(0),r=i(7),a=i(2);!function(t){t[t.EventsBand=0]="EventsBand",t[t.MinimapBand=1]="MinimapBand"}(e.BandType||(e.BandType={}));e.default=class{constructor(t){this.config=t,this.defaultZoomLevel=0}get offsetX(){return this._offsetX}set offsetX(t){this.prevOffsetX=this.offsetX||t,this._offsetX=t}get zoomLevel(){return this._zoomLevel}set zoomLevel(t){t<0&&(t=0),this.visibleRatio=r.visibleRatio(t),this.width=Math.round(s.default.viewportWidth/this.visibleRatio),this.pixelsPerMillisecond=this.width/s.default.time,this.time=this.visibleRatio*s.default.time,this.granularity=n.getGranularity(this.pixelsPerMillisecond),this.nextDate=n.subsequentDate(this.granularity),this.prevZoomLevel=this.zoomLevel||t,this._zoomLevel=t,this.setHorizontalProps()}setVerticalProps(){this.visibleHeight=Math.round(this.config.heightRatio*s.default.viewportHeight),this.availableHeight=this.visibleHeight-o.DATE_BAR_HEIGHT,this.availableHeight/this.visibleHeight<.666&&(this.availableHeight=.666*this.visibleHeight),this.visibleRowsCount=Math.floor(this.availableHeight/o.EVENT_ROW_HEIGHT)-1,this.top=Math.round(this.config.topOffsetRatio*s.default.viewportHeight)}setHorizontalProps(){this.from=s.default.center-this.time/2,this.to=s.default.center+this.time/2,this.offsetX=(s.default.from-this.from)*this.pixelsPerMillisecond}init(t){this.zoomLevel=this.config.zoomLevel,this.setVerticalProps(),a.default.registerModel(this)}resize(){this.zoomLevel=this.zoomLevel,this.setVerticalProps()}update(){this.setHorizontalProps()}updateConfig(t){Object.keys(t).forEach(e=>{this.config.hasOwnProperty(e)&&(this.config[e]=t[e])})}positionAtTimestamp(t){return Math.round((t-this.from)*this.pixelsPerMillisecond)}timestampAtProportion(t){return s.default.from+s.default.time*t}timestampAtPosition(t){return this.from+t/this.pixelsPerMillisecond}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],s=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function o(t){return s[t.getUTCMonth()]}function r(t){const e=t.getUTCDate();return`${n[t.getUTCDay()]}, ${e}${function(t){return["st","nd","rd"][((t+90)%100-10)%10-1]||"th"}(e)}`}function a(t){return t.getUTCHours().toString().padStart(2,"0")}function l(t){return t.getUTCMinutes().toString().padStart(2,"0")}function h(t){return t.getUTCSeconds().toString().padStart(2,"0")}function u(t){return t.getUTCMilliseconds().toString().padStart(3,"0")}function d(t){return"YEAR"===t||"YEAR_5"===t||"DECADE"===t||"DECADE_5"===t||"CENTURY"===t||"CENTURY_5"===t||"MILLENIUM"===t}e.formatDate=((t,e)=>{if(null==t)return"∞";const i=new Date(t);let n=i.getUTCFullYear().toString();return d(e)?n:(n=`${o(i)} ${n}`,"MONTH"===e?n:(n=`${r(i)} ${n}`,"DAY"===e?n:(n=`${n} at ${a(i)}:`,"HOUR"===e?`${n}00`:(n=`${n}${l(i)}`,"MINUTE"===e?n:(n=`${n}:${h(i)}`,"SECOND"===e?n:`${n}.${u(i)}`)))))}),e.getGranularity=(t=>t>58?"MILLISECOND":t>12?"MILLISECOND_10":t>2.3?"MILLISECOND_50":t>1.5?"MILLISECOND_100":t>.4?"MILLISECOND_500":t>.00112?"SECOND":t>112e-6?"MINUTE":t>112e-7?"HOUR":t>8e-7?"DAY":t>2.6e-7?"WEEK":t>2.2e-8?"MONTH":t>2.2e-9?"YEAR":t>3.3e-10?"YEAR_5":t>1.6e-10?"DECADE":t>8e-11?"DECADE_5":t>1.5e-11?"CENTURY":t>5e-12?"CENTURY_5":"MILLENIUM"),e.getStep=(t=>{if("YEAR"===t)return 1;if("YEAR_5"===t)return 5;if("DECADE"===t)return 10;if("DECADE_5"===t)return 50;if("CENTURY"===t)return 100;if("CENTURY_5"===t)return 500;if("MILLENIUM"===t)return 1e3;if("MILLISECOND"===t)return 1;if("MILLISECOND_10"===t)return 10;if("MILLISECOND_50"===t)return 50;if("MILLISECOND_100"===t)return 100;if("MILLISECOND_500"===t)return 500;throw new RangeError("[getStep] Only steps with a granularity greater than 'year' calculated")}),e.subsequentDate=function(t){return d(t)?i=>{let n=new Date(i),s=n.getUTCFullYear()+1;if("YEAR"!==t){const i=e.getStep(t);for(;s%i!=0;)s+=1}return s>-1&&s<100?(n.setUTCFullYear(s),n.getTime()):Date.UTC(s,0,1)}:"MONTH"===t?t=>{const e=new Date(t);return Date.UTC(e.getUTCFullYear(),e.getUTCMonth()+1,1)}:"WEEK"===t?t=>{const e=new Date(t);return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()+7)}:"DAY"===t?t=>{const e=new Date(t);return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate()+1)}:"HOUR"===t?t=>{const e=new Date(t);return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours()+1)}:"MINUTE"===t?t=>{const e=new Date(t);return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes()+1)}:"SECOND"===t?t=>{const e=new Date(t);return Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate(),e.getUTCHours(),e.getUTCMinutes(),e.getUTCSeconds()+1)}:"MILLISECOND"===t.slice(0,"MILLISECOND".length)?i=>{const n=e.getStep(t),s=new Date(i);let o=s.getUTCMilliseconds()+1;return n>1&&(o=o+n-o%n),Date.UTC(s.getUTCFullYear(),s.getUTCMonth(),s.getUTCDate(),s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds(),o)}:void 0},e.byDate=function(t,e){const i=null!=t.dmin?t.dmin:t.d,n=null!=e.dmin?e.dmin:e.d;if(i<n)return-1;if(i>n)return 1;const s=null!=t.dmax?t.dmax:t.ed,o=null!=e.dmax?e.dmax:e.ed;return s<o?-1:s>o?1:0};e.labelBody=((t,e)=>{const i=new Date(t);return d(e)?i.getUTCFullYear().toString():"MONTH"===e?o(i):"WEEK"===e?`${o(i)}, 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)}`:"DAY"===e?`${r(i)} ${o(i)}`:"HOUR"===e?`${a(i)}:00`:"MINUTE"===e?`${a(i)}:${l(i)}`:"SECOND"===e?`${a(i)}:${l(i)}:${h(i)}`:"MILLISECOND"===e.slice(0,"MILLISECOND".length)?`${a(i)}:${l(i)}:${h(i)}.${u(i)}`:void 0})},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});class n{constructor(){this.eventsListeners=[]}dispatch(t,e){const i=null!=e?new CustomEvent(t,{detail:e}):new CustomEvent(t);document.dispatchEvent(i)}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=[]}}e.EventBus=n,e.default=new n},function(t,e,i){"use strict";function n(t){return Math.pow(2,-1*t)}function s(t){if(null==t)return null;return new Date(t).toUTCString()}Object.defineProperty(e,"__esModule",{value:!0}),e.debounce=((t,e)=>{let i;return()=>{clearTimeout(i),i=setTimeout(t,e)}}),e.visibleRatio=n,e.createRange=function(t){return Array.apply(null,{length:t}).map(Number.call,Number)},e.selectRandom=function(t,e){const i=[];for(;i.length<e;){const n=t[Math.floor(Math.random()*t.length)];(-1===i.indexOf(n)||t.length<e)&&i.push(n)}return i},e.calcPixelsPerMillisecond=function(t,e,i){return t/n(e)/i},e.logEvent=function(t,...e){console.log(t.lbl,t,s(t.from),s(t.to),e)}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});e.DomainConfig=class{};class n{constructor(){this.heightRatio=1,this.rulers=!0,this.rulerLabels=!0,this.topOffsetRatio=0,this.zoomLevel=0}}e.BandConfig=n;e.MinimapBandConfig=class extends n{constructor(){super(...arguments),this.indicatorFor=0,this.targets=[]}};e.EventsBandConfig=class extends n{};e.default=class{}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(1);e.TimelineProps=n.Props;const s=i(8);e.TimelineConfig=s.default;const o=i(10),r=i(3),a=i(7);e.calcPixelsPerMillisecond=a.calcPixelsPerMillisecond;const l=i(12);e.OrderedTimeline=l.OrderedTimeline,e.orderEvents=l.orderEvents;const h=i(13),u=i(14),d=i(15),c=i(18),f=i(19),p=i(20);e.MinimapBand=p.default;const m=i(21);e.EventsBand=m.default;const v=i(5);e.formatDate=v.formatDate;const g=i(11);e.Ev3ntLocation=g.Ev3ntLocation,e.RawEv3nt=g.RawEv3nt,e.Ev3nt=g.Ev3nt,e.Voyage=g.Voyage;const E=i(4),w=i(0);e.EventType=w.EventType;e.default=class extends h.default{constructor(t){super(),this.appendToWrapper=(t=>{let e=t.render();Array.isArray(e)||(e=[e]),e.forEach(t=>this.wrapper.appendChild(t))}),n.default.init(t),t.rootElement.appendChild(this.render()),this.popup=new f.default(this.wrapper);const e=a.debounce(this.resize,600);window.addEventListener("resize",e)}hidePopup(){this.popup.hide()}showPopup(t){this.popup.show(t)}render(){this.wrapper=r.default("div","wrapper",["box-sizing: border-box","height: 100%","overflow: hidden","position: relative","user-select: none","width: 100%"]),this.views=n.default.bands.map(t=>t.type===E.BandType.EventsBand?new u.default(t):new o.default(t)),this.views.push(new d.default),this.views.forEach(this.appendToWrapper),this.renderLabels();const t=r.default("div","red-line",["background-color: rgb(126, 0, 0)","bottom: 0","left: calc(50% - 1px)","position: absolute","top: 0","width: 2px","z-index: 4"]);return this.wrapper.appendChild(t),this.wrapper}renderLabels(){n.default.bands.filter(t=>t.type===E.BandType.EventsBand&&null!=t.config.label).map(t=>new c.default(t)).forEach(this.appendToWrapper)}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(4),s=i(1),o=i(3),r=i(6),a=i(2),l=i(0);e.default=class{constructor(t){this.band=t,this.onMouseDown=(t=>{document.addEventListener("mouseup",this.onMouseUp),this.dragStartTime=Date.now(),this.dragStartPosition=[t.clientX,t.clientY],this.dragOffsetX=t.clientX,this.dragOffsetY=t.clientY}),this.onMouseMove=(t=>{if(null==this.dragOffsetX)return;const e=t.clientY-this.dragOffsetY,i=t.clientX-this.dragOffsetX;if(this.band.type===n.BandType.EventsBand){const t=this.band;(0!==t.offsetY||Math.abs(e)>Math.abs(i)&&Math.abs(e)>5)&&(t.offsetY=e)}const o=i/this.band.pixelsPerMillisecond;s.default.center-=o,a.default.nextFrame(),this.dragOffsetX=t.clientX,this.dragOffsetY=t.clientY}),this.onMouseUp=(t=>{this.lastDragInterval=Date.now()-this.dragStartTime,this.dispatchScrollDoneEvent(t),this.dragOffsetX=null,this.dragOffsetY=null,document.removeEventListener("mouseup",this.onMouseUp)}),this.onDblClick=(t=>{const e=this.band.timestampAtPosition(t.clientX);a.default.goTo(e)})}render(){return this.rootElement=o.default("div","band-wrap",["position: absolute","z-index: 2"],[`height: ${this.band.visibleHeight}px`,`top: ${this.band.top}px`,`width: ${s.default.viewportWidth}px`]),r.default.register("mousedown",this.onMouseDown,this.rootElement),r.default.register("mousemove",this.onMouseMove,this.rootElement),r.default.register("dblclick",this.onDblClick,this.rootElement),this.rootElement}dispatchScrollDoneEvent(t){const e=[this.dragStartPosition[0]-t.clientX,this.dragStartPosition[1]-t.clientY].map(Math.abs).some(t=>t>5);(this.lastDragInterval>200||e)&&r.default.dispatch(l.EventType.ScrollDone)}resize(){this.rootElement.style.cssText=`height: ${this.band.visibleHeight}px; top: ${this.band.top}px; width: ${s.default.viewportWidth}px;`}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(0);!function(t){t.NONE="none",t.JPG="jpg",t.SVG="svg",t.GIF="gif",t.PNG="png"}(e.ImageFileType||(e.ImageFileType={}));e.Ev3ntLocation=class{};e.Voyage=class{};class s{}e.RawEv3nt=s;e.Ev3nt=class extends s{constructor(t,e){super();for(const e in t)null!=t[e]&&(this[e]=t[e]);if(null==this.lbl&&(this.lbl="NO LABEL"),null==this.id&&(this.id="id_"+crypto.getRandomValues(new Uint8Array(4)).join("_")),this.from=this.dmin||this.d,this.to=this.dmax||this.ed,null==this.to&&(this.to=this.from),this.time=this.to-this.from,null!=e){const t=Math.round(2*n.EVENT_HEIGHT/e);let i=this.lbl.length*n.PIXELS_PER_LETTER/e+t;i=i>this.time?i-this.time:0,this.screenTo=Math.round(this.from+this.time+i)}}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(0),s=i(11),o=i(7);class r{}e.OrderedTimeline=r,e.orderEvents=function(t){if(null==t.bands||!t.bands.length)return new r;let e,i=t.bands.reduce((t,e)=>{const i=e.events[0];return Math.min(t,i.dmin||1/0,i.d||1/0)},1/0),a=t.bands.reduce((t,e)=>{const i=e.events.reduce((t,e)=>Math.max(t,e.d||-1/0,e.ed||-1/0,e.dmax||-1/0),-1/0);return Math.max(i,t)},-1/0);null!=t.parent&&(e=new s.Ev3nt(t.parent),i=Math.min(i,e.dmin||1/0,e.d||1/0),a=Math.max(a,e.ed||-1/0,e.dmax||-1/0));const l=a-i;return{bands:t.bands.map(function(e){const i=o.calcPixelsPerMillisecond(t.viewportWidth,e.zoomLevel,l),r=[-1/0],a=Math.round(2*n.EVENT_ROW_HEIGHT/i);function h(t,e){return(null==r[t+1]||r[t+1]<e)&&(null==r[t+2]||r[t+2]<e)}return{events:e.events.map(function(t){const e=new s.Ev3nt(t,i);let n;if(e.img){const t=e.time?e.from:e.from-a/2,i=e.time?e.from+a:e.from+a/2;if((n=r.findIndex(e=>t>e))>-1){let e=!1;for(;!e&&!(e=h(n,t));)-1===(n=r.findIndex((e,i)=>i>n&&t>e))&&(e=!0)}-1===n?(n=r.push(e.screenTo)-1,r.push(i),r.push(i)):(r[n]=e.screenTo,r[n+1]=i,r[n+2]=i)}else-1===(n=r.findIndex(t=>e.from>t))?n=r.push(e.screenTo)-1:r[n]=e.screenTo;return e.row=n,e}),zoomLevel:e.zoomLevel,pixelsPerMillisecond:i,rowCount:r.length}}),from:i,parent:e,time:l,to:a}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(2),s=i(1),o=i(0);e.default=class{constructor(){this.animator=n.default,this.resize=(()=>{s.default.resize();for(const t of s.default.bands)t.resize();for(const t of this.views)t.resize();this.animator.nextFrame()}),document.addEventListener("keydown",t=>{189===t.keyCode&&s.default.controlBand.zoomOut(),187===t.keyCode&&s.default.controlBand.zoomIn()})}on(t,e){const i={centerchange:o.EventType.CenterChange,pause:o.EventType.Pause,play:o.EventType.Play,scrolldone:o.EventType.ScrollDone,select:o.EventType.Select,zoomdone:o.EventType.ZoomDone};if(Object.keys(i).indexOf(t)>-1){const n=i[t];let r;r=n===o.EventType.CenterChange?()=>e(s.default):n===o.EventType.Select?t=>e(t.detail):e,document.addEventListener(n,r)}}reload(){this.resize()}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(10),s=i(6),o=i(0);e.default=class extends n.default{constructor(t){super(t),this.band=t,this.onWheel=(t=>{0===Math.abs(t.deltaX)&&0!==t.deltaY&&(t.deltaY<0&&this.zoomOut(),t.deltaY>0&&this.zoomIn())}),this.onClick=(t=>{if(this.lastDragInterval>175)return;const e=this.band.getEventByCoordinates(t.clientX,t.clientY);s.default.dispatch(o.EventType.Select,e)})}render(){const t=super.render();return s.default.register("click",this.onClick,this.rootElement),s.default.register("wheel",this.onWheel,this.rootElement),t}zoomIn(){this.band.zoomIn()}zoomOut(){this.band.zoomOut()}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(16),s=i(3),o=i(1),r=i(0),a=i(2),l=i(17),h=i(6);e.default=class{constructor(){this.indicatorsDrawn=!1,this.onImgLoad=(t=>{const e=i=>{t.image.removeEventListener("load",e),t.image.removeEventListener("error",e),"error"!==i.type?(t.image.width>t.image.height?(t.image.height=Math.round(t.image.height*(r.IMAGE_BOUNDING_BOX/t.image.width)),t.image.width=r.IMAGE_BOUNDING_BOX):(t.image.width=Math.round(t.image.width*(r.IMAGE_BOUNDING_BOX/t.image.height)),t.image.height=r.IMAGE_BOUNDING_BOX),this.drawImage(t)):t.image=null};return e}),this.onAnimationDone=(()=>{}),this.update=(()=>{for(const t of o.default.eventsBands)this.drawEventsBand(t);for(const t of o.default.minimapBands)this.drawMinimapBand(t);this.drawIndicators(),this.updateImages()}),a.default.registerView(this),h.default.register(r.EventType.ZoomDone,this.onAnimationDone),h.default.register(r.EventType.ScrollDone,this.onAnimationDone)}updateImages(){return n.__awaiter(this,void 0,void 0,function*(){for(const t of o.default.eventsBands)for(const e of t.visibleEvents)if(null!=e.img)if(null==e.image){const t=`${o.default.imagePath}/${e.wid}__${r.IMAGE_SIZE}.${e.img}`;e.image=new Image;const i=this.onImgLoad(e);e.image.addEventListener("load",i),e.image.addEventListener("error",i),e.image.src=t}else this.drawImage(e)})}drawImage(t){if(null==t.image||!t.image.complete||!t.image.naturalWidth)return;const e=t.time?t.left:t.left-t.image.width/2-r.IMAGE_BORDER_SIZE,i=t.top-t.image.height;this.ctx.fillStyle=t.color,this.ctx.fillRect(e,i-2*r.IMAGE_BORDER_SIZE,t.image.width+2*r.IMAGE_BORDER_SIZE,t.image.height+2*r.IMAGE_BORDER_SIZE),this.ctx.drawImage(t.image,e+r.IMAGE_BORDER_SIZE,i-r.IMAGE_BORDER_SIZE,t.image.width,t.image.height)}render(){return this.canvas=s.default("canvas","main",["position: absolute"]),this.canvas.width=o.default.viewportWidth,this.canvas.height=o.default.viewportHeight,this.ctx=this.canvas.getContext("2d"),this.indicatorsCanvas=s.default("canvas","indicators",["position: absolute"],["z-index: 1"]),this.indicatorsCanvas.width=o.default.viewportWidth,this.indicatorsCanvas.height=o.default.viewportHeight,this.indicatorsCtx=this.indicatorsCanvas.getContext("2d"),this.update(),[this.canvas,this.indicatorsCanvas]}resize(){this.indicatorsCanvas.width=o.default.viewportWidth,this.indicatorsCanvas.height=o.default.viewportHeight,this.canvas.width=o.default.viewportWidth,this.canvas.height=o.default.viewportHeight,this.indicatorsDrawn=!1}clear(t){this.ctx.clearRect(0,t.top,this.canvas.width,t.visibleHeight)}drawEventsBand(t){this.clear(t),l.default(this.ctx,t);for(const e of t.visibleEvents)if(e.time){let t=e.left,i=e.width;if(e.uncertain_from_width>1){const n=this.ctx.createLinearGradient(e.left,0,e.left+e.uncertain_from_width,0);n.addColorStop(0,"white"),n.addColorStop(1,e.color),this.ctx.fillStyle=n,this.ctx.fillRect(e.left,e.top,e.uncertain_from_width,r.EVENT_HEIGHT),t=e.left+e.uncertain_from_width,i-=e.uncertain_from_width}if(e.uncertain_to_width>1){const n=t+(i-=e.uncertain_to_width),s=n+e.uncertain_to_width,o=this.ctx.createLinearGradient(n,0,s,0);o.addColorStop(0,e.color),o.addColorStop(1,"white"),this.ctx.fillStyle=o,this.ctx.fillRect(n,e.top,e.uncertain_to_width,r.EVENT_HEIGHT)}this.ctx.fillStyle=e.color,this.ctx.fillRect(t,e.top,i,r.EVENT_HEIGHT)}else this.ctx.moveTo(e.left,e.top+r.EVENT_HEIGHT/2),this.ctx.beginPath(),this.ctx.arc(e.left,e.top+r.EVENT_HEIGHT/2,r.EVENT_HEIGHT/3,0,2*Math.PI),this.ctx.fillStyle=e.color,this.ctx.fill();this.drawEventsText(t)}drawEventsText(t){this.ctx.font=`${r.FONT_SIZE}px sans-serif`,this.ctx.fillStyle="rgb(40, 40, 40)";for(const e of t.visibleEvents){let t=e.left;e.left<0&&0!==e.time&&(t=-e.uncertain_from_width);const i=t+(e.time?r.FONT_SIZE/3:r.FONT_SIZE/1.2)+e.uncertain_from_width,n=e.top+r.FONT_SIZE+(r.EVENT_HEIGHT-r.FONT_SIZE)/2-2;this.ctx.fillText(e.lbl,Math.round(i),Math.round(n))}}drawMinimapBand(t){if(t.isDrawn&&t.prevOffsetX===t.offsetX&&t.prevZoomLevel===t.zoomLevel)return;this.clear(t),l.default(this.ctx,t);const e=t.draw();this.ctx.drawImage(e,0,t.top,o.default.viewportWidth,t.availableHeight),t.isDrawn=!0}drawIndicators(){if(!this.indicatorsDrawn||!o.default.eventsBands.every(t=>t.prevZoomLevel===t.zoomLevel)){this.indicatorsCtx.clearRect(0,0,o.default.viewportWidth,o.default.viewportHeight),this.indicatorsCtx.beginPath();for(const t of o.default.minimapBands){const e=o.default.eventsBands[t.config.indicatorFor],i=Math.round(t.config.topOffsetRatio*o.default.viewportHeight),n=t.positionAtTimestamp(e.from);this.indicatorsCtx.rect(0,i,n,t.visibleHeight);const s=t.positionAtTimestamp(e.to);this.indicatorsCtx.rect(s,i,o.default.viewportWidth,t.visibleHeight),this.indicatorsCtx.rect(n,i+t.availableHeight,s-n,t.visibleHeight-t.availableHeight)}this.indicatorsCtx.fillStyle="rgba(0, 0, 0, .04)",this.indicatorsCtx.fill(),this.indicatorsCtx.closePath(),this.indicatorsDrawn=!0}}}},function(t,e,i){"use strict";i.r(e),i.d(e,"__extends",function(){return s}),i.d(e,"__assign",function(){return o}),i.d(e,"__rest",function(){return r}),i.d(e,"__decorate",function(){return a}),i.d(e,"__param",function(){return l}),i.d(e,"__metadata",function(){return h}),i.d(e,"__awaiter",function(){return u}),i.d(e,"__generator",function(){return d}),i.d(e,"__exportStar",function(){return c}),i.d(e,"__values",function(){return f}),i.d(e,"__read",function(){return p}),i.d(e,"__spread",function(){return m}),i.d(e,"__await",function(){return v}),i.d(e,"__asyncGenerator",function(){return g}),i.d(e,"__asyncDelegator",function(){return E}),i.d(e,"__asyncValues",function(){return w}),i.d(e,"__makeTemplateObject",function(){return _}),i.d(e,"__importStar",function(){return T}),i.d(e,"__importDefault",function(){return b}); | ||
/*! ***************************************************************************** | ||
Copyright (c) Microsoft Corporation. All rights reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
this file except in compliance with the License. You may obtain a copy of the | ||
License at http://www.apache.org/licenses/LICENSE-2.0 | ||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
MERCHANTABLITY OR NON-INFRINGEMENT. | ||
See the Apache Version 2.0 License for specific language governing permissions | ||
and limitations under the License. | ||
***************************************************************************** */ | ||
var n=function(t,e){return(n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var i in e)e.hasOwnProperty(i)&&(t[i]=e[i])})(t,e)};function s(t,e){function i(){this.constructor=t}n(t,e),t.prototype=null===e?Object.create(e):(i.prototype=e.prototype,new i)}var o=function(){return(o=Object.assign||function(t){for(var e,i=1,n=arguments.length;i<n;i++)for(var s in e=arguments[i])Object.prototype.hasOwnProperty.call(e,s)&&(t[s]=e[s]);return t}).apply(this,arguments)};function r(t,e){var i={};for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&e.indexOf(n)<0&&(i[n]=t[n]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var s=0;for(n=Object.getOwnPropertySymbols(t);s<n.length;s++)e.indexOf(n[s])<0&&(i[n[s]]=t[n[s]])}return i}function a(t,e,i,n){var s,o=arguments.length,r=o<3?e:null===n?n=Object.getOwnPropertyDescriptor(e,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(t,e,i,n);else for(var a=t.length-1;a>=0;a--)(s=t[a])&&(r=(o<3?s(r):o>3?s(e,i,r):s(e,i))||r);return o>3&&r&&Object.defineProperty(e,i,r),r}function l(t,e){return function(i,n){e(i,n,t)}}function h(t,e){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(t,e)}function u(t,e,i,n){return new(i||(i=Promise))(function(s,o){function r(t){try{l(n.next(t))}catch(t){o(t)}}function a(t){try{l(n.throw(t))}catch(t){o(t)}}function l(t){t.done?s(t.value):new i(function(e){e(t.value)}).then(r,a)}l((n=n.apply(t,e||[])).next())})}function d(t,e){var i,n,s,o,r={label:0,sent:function(){if(1&s[0])throw s[1];return s[1]},trys:[],ops:[]};return o={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function a(o){return function(a){return function(o){if(i)throw new TypeError("Generator is already executing.");for(;r;)try{if(i=1,n&&(s=2&o[0]?n.return:o[0]?n.throw||((s=n.return)&&s.call(n),0):n.next)&&!(s=s.call(n,o[1])).done)return s;switch(n=0,s&&(o=[2&o[0],s.value]),o[0]){case 0:case 1:s=o;break;case 4:return r.label++,{value:o[1],done:!1};case 5:r.label++,n=o[1],o=[0];continue;case 7:o=r.ops.pop(),r.trys.pop();continue;default:if(!(s=(s=r.trys).length>0&&s[s.length-1])&&(6===o[0]||2===o[0])){r=0;continue}if(3===o[0]&&(!s||o[1]>s[0]&&o[1]<s[3])){r.label=o[1];break}if(6===o[0]&&r.label<s[1]){r.label=s[1],s=o;break}if(s&&r.label<s[2]){r.label=s[2],r.ops.push(o);break}s[2]&&r.ops.pop(),r.trys.pop();continue}o=e.call(t,r)}catch(t){o=[6,t],n=0}finally{i=s=0}if(5&o[0])throw o[1];return{value:o[0]?o[1]:void 0,done:!0}}([o,a])}}}function c(t,e){for(var i in t)e.hasOwnProperty(i)||(e[i]=t[i])}function f(t){var e="function"==typeof Symbol&&t[Symbol.iterator],i=0;return e?e.call(t):{next:function(){return t&&i>=t.length&&(t=void 0),{value:t&&t[i++],done:!t}}}}function p(t,e){var i="function"==typeof Symbol&&t[Symbol.iterator];if(!i)return t;var n,s,o=i.call(t),r=[];try{for(;(void 0===e||e-- >0)&&!(n=o.next()).done;)r.push(n.value)}catch(t){s={error:t}}finally{try{n&&!n.done&&(i=o.return)&&i.call(o)}finally{if(s)throw s.error}}return r}function m(){for(var t=[],e=0;e<arguments.length;e++)t=t.concat(p(arguments[e]));return t}function v(t){return this instanceof v?(this.v=t,this):new v(t)}function g(t,e,i){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var n,s=i.apply(t,e||[]),o=[];return n={},r("next"),r("throw"),r("return"),n[Symbol.asyncIterator]=function(){return this},n;function r(t){s[t]&&(n[t]=function(e){return new Promise(function(i,n){o.push([t,e,i,n])>1||a(t,e)})})}function a(t,e){try{!function(t){t.value instanceof v?Promise.resolve(t.value.v).then(l,h):u(o[0][2],t)}(s[t](e))}catch(t){u(o[0][3],t)}}function l(t){a("next",t)}function h(t){a("throw",t)}function u(t,e){t(e),o.shift(),o.length&&a(o[0][0],o[0][1])}}function E(t){var e,i;return e={},n("next"),n("throw",function(t){throw t}),n("return"),e[Symbol.iterator]=function(){return this},e;function n(n,s){e[n]=t[n]?function(e){return(i=!i)?{value:v(t[n](e)),done:"return"===n}:s?s(e):e}:s}}function w(t){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var e,i=t[Symbol.asyncIterator];return i?i.call(t):(t=f(t),e={},n("next"),n("throw"),n("return"),e[Symbol.asyncIterator]=function(){return this},e);function n(i){e[i]=t[i]&&function(e){return new Promise(function(n,s){(function(t,e,i,n){Promise.resolve(n).then(function(e){t({value:e,done:i})},e)})(n,s,(e=t[i](e)).done,e.value)})}}}function _(t,e){return Object.defineProperty?Object.defineProperty(t,"raw",{value:e}):t.raw=e,t}function T(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var i in t)Object.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e.default=t,e}function b(t){return t&&t.__esModule?t:{default:t}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(1),s=i(0),o=i(5);function r(t,e){return"CENTURY"===e.granularity&&new Date(t).getUTCFullYear()%1e3==0||("YEAR_5"===e.granularity&&new Date(t).getUTCFullYear()%50==0||"YEAR"===e.granularity&&new Date(t).getUTCFullYear()%5==0)}function a(t,e,i,n,s){const r=e.positionAtTimestamp(i);t.moveTo(r,n),t.lineTo(r,s),e.config.rulerLabels&&t.fillText(o.labelBody(i,e.granularity),r+3,s-3)}e.default=function(t,e){if(!e.config.rulers)return;let i=e.nextDate(e.from);const o=e.config.topOffsetRatio*n.default.viewportHeight,l=e.config.heightRatio*n.default.viewportHeight,h=[],u=[];for(;i<e.to;)r(i,e)?u.push(i):h.push(i),i=e.nextDate(i);t.beginPath(),t.font=`${s.FONT_SIZE}px sans-serif`,t.fillStyle="rgb(205, 205, 205)";for(const i of h)a(t,e,i,o,o+l);t.strokeStyle="rgb(235, 235, 235)",t.stroke(),t.beginPath(),t.font=`${1.2*s.FONT_SIZE}px sans-serif`,t.fillStyle="rgb(120, 120, 120)";for(const i of u)a(t,e,i,o,o+l);t.strokeStyle="rgb(150, 150, 150)",t.stroke()}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(3);e.default=class{constructor(t){this.band=t}render(){const t=n.default("div","events-label-wrapper",["border-top: 1px solid #CCC","pointer-events: none","position: absolute","width: 100%","z-index: 3"],[`top: ${100*this.band.config.topOffsetRatio}%`]),e=n.default("div","events-label",["background: white","border-bottom-right-radius: 4px","box-shadow: 1px 2px 4px #AAA","color: #444","display: inline-block","font-family: sans-serif","font-size: .8em","padding: 4px 8px"]);return e.innerText=this.band.config.label,t.appendChild(e),t}resize(){}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(3),s=i(1),o=i(0),r=i(5),a=i(2),l=14;e.default=class{constructor(t){this.rootElement=t,this.update=(()=>{this.event&&this.setPosition()}),this.loadImage=(()=>{this.el.querySelector("img").removeEventListener("load",this.loadImage),this.setWidth(),this.setPosition()}),this.el=n.default("div"),this.el.id="popup",this.el.style.position="absolute",this.el.style.zIndex="10",this.hide(),this.rootElement.appendChild(this.el),this.el.addEventListener("click",t=>{t.target.matches("#popup-close")&&this.hide()}),a.default.registerView(this)}hide(){this.event=null,this.el.style.width="auto",this.el.style.visibility="hidden",this.el.classList.remove("bottom")}setWidth(){const t=this.el.getBoundingClientRect();this.el.style.width=`${t.width}px`}setPosition(){const t=this.el.getBoundingClientRect();if(this.event.left+this.event.width<l||this.event.left>s.default.viewportWidth-l)return void(this.el.style.visibility="hidden");let e=this.event.left+this.event.width/2-t.width/2;e<l&&(e=l),e+t.width>s.default.viewportWidth-l&&(e=s.default.viewportWidth-t.width-l),this.el.style.left=`${e}px`;let i=this.event.top+o.EVENT_HEIGHT+l;i+t.height>s.default.viewportHeight-l&&(i=this.event.top-t.height-l,this.el.classList.add("bottom")),this.el.style.top=`${i}px`,this.el.style.visibility="visible"}show(t){this.hide(),this.event=t,this.el.innerHTML=function(t){return`\n\t\t<img alt="noimage" src="" />\n\t\t<div class="metadata">\n\t\t\t<h2 class="label">${t.lbl}</h2>\n\t\t\t<div class="description">${t.dsc||""}</div>\n\t\t\t<br />\n\t\t\t<br />\n\t\t\t<div class="from">${r.formatDate(t.from,t.dmin_g||t.d_g)}</div>\n\t\t\t${t.time?`<div class="to">${r.formatDate(t.to,t.dmax_g||t.ed_g)}</div>`:""}\n\t\t</div>\n\t\t<div id="popup-close">✖</div>\n\t`}(t),this.el.querySelector(".label").style.color=t.color;const e=this.el.querySelector("img");t.img?(e.setAttribute("alt",`Image of ${t.lbl}`),e.addEventListener("load",this.loadImage),e.src=t.image.src.replace("32","128")):(e.src=null,e.setAttribute("alt","noimage"),this.setWidth(),this.setPosition())}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(4),s=i(8),o=i(1),r=i(3);e.default=class extends n.default{constructor(t){super(function(t){const e=Object.assign({},new s.MinimapBandConfig,t);return e.targets.length||e.targets.push(0),e}(t)),this.type=n.BandType.MinimapBand,this.canvas=r.default("canvas"),this.ctx=this.canvas.getContext("2d"),this.nextCanvas=r.default("canvas"),this.nextCtx=this.nextCanvas.getContext("2d"),this.isDrawn=!1}init(){super.init(),this.maxRowCount=this.config.targets.reduce((t,e)=>{const{rowCount:i}=o.default.eventsBands[e];return Math.max(t,i)},0);const t=this.availableHeight/this.maxRowCount;this.eventHeight=t<1?1:Math.floor(t),this.canvas.width=o.default.viewportWidth,this.canvas.height=this.maxRowCount*this.eventHeight,this.nextCanvas.width=this.canvas.width,this.nextCanvas.height=this.canvas.height}resize(){super.resize(),this.isDrawn=!1}draw(){return this.isDrawn?this.updateNextCanvas():this.drawEvents(),this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.drawImage(this.nextCanvas,0,0),this.canvas}drawEvents(t=this.from,e=this.to){this.nextCtx.beginPath(),this.config.targets.forEach(i=>{const n=o.default.eventsBands[i];for(const i of n.events){if(i.from>e||i.to<t)continue;const n=this.positionAtTimestamp(i.from),s=this.maxRowCount-(i.row+2)*this.eventHeight,o=Math.round(i.time*this.pixelsPerMillisecond),r=o<1?1:o;this.nextCtx.fillStyle="rgb(190, 190, 190)",this.nextCtx.fillRect(n,s,r,this.eventHeight),i.img&&(this.nextCtx.fillStyle="rgb(240, 240, 240)",this.nextCtx.fillRect(n,s-2*this.eventHeight,2*this.eventHeight,2*this.eventHeight))}})}updateNextCanvas(){const t=Math.round(this.offsetX-this.prevOffsetX);if(0===t)return this.canvas;let e,i;this.nextCtx.clearRect(0,0,this.nextCanvas.width,this.nextCanvas.height),this.nextCtx.drawImage(this.canvas,t,0),t<0?(e=this.timestampAtPosition(o.default.viewportWidth+t),i=this.to):(e=this.from,i=this.timestampAtPosition(t)),this.drawEvents(e,i)}}},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});const n=i(4),s=i(8),o=i(2),r=i(0),a=i(1),l=i(5);e.default=class extends n.default{constructor(t){super(Object.assign({},new s.EventsBandConfig,t)),this.type=n.BandType.EventsBand,this.events=[],this.rowCount=0,this.visibleEvents=[],this._offsetY=0,null!=this.config.events&&this.config.events.sort(l.byDate)}get offsetY(){return this._offsetY}set offsetY(t){this._offsetY+=t,this._offsetY<0&&(this._offsetY=0);const e=this.height>this.availableHeight?this.height-this.availableHeight+r.EVENT_ROW_HEIGHT:0;this._offsetY>e&&(this._offsetY=e);const i=this._offsetY/r.EVENT_ROW_HEIGHT;this.lowestVisibleRow=Math.ceil(i),this.highestVisibleRow=this.lowestVisibleRow+this.visibleRowsCount}init(t){super.init(),this.events=t.events,this.rowCount=t.rowCount,this.height=r.EVENT_ROW_HEIGHT*this.rowCount,this.offsetY=0,this.updateEvents()}getColor(t,e){const i=[49,220,215];let n;if(a.default.center>e)n=a.default.center-e;else{if(!(a.default.center<t))return`rgb(${i.join(", ")})`;n=t-a.default.center}const s=n/(this.time/2),o=a.default.center>e?[253,231,37]:[204,104,232];return`rgb(${i.map((t,e)=>t+(o[e]-t)*s).join(", ")})`}updateEvents(){this.visibleEvents=this.events.filter(t=>!(t.from>this.to||t.to<this.from)&&t.row>=this.lowestVisibleRow&&t.row<=this.highestVisibleRow).map(t=>{if(t.left=this.positionAtTimestamp(t.from),t.width=Math.round(t.time*this.pixelsPerMillisecond),t.time&&t.width<1&&(t.width=1),t.uncertain_from_width=0,null!=t.dmin){let e;if(null!=t.d)e=t.d;else if(null!=t.ed)e=t.ed;else{if(null==t.dmax)throw Error(["updateEvents","Width uncertain from is not definable",JSON.stringify(t)].join("\n"));e=t.dmin+(t.dmax-t.dmin)/2}t.uncertain_from_width=(e-t.dmin)*this.pixelsPerMillisecond}if(t.uncertain_to_width=0,null!=t.dmax){let e;if(null!=t.ed)e=t.ed;else if(null!=t.d)e=t.d;else{if(null==t.dmin)throw Error(["updateEvents","Width uncertain to is not definable",JSON.stringify(t)].join("\n"));e=t.dmin+(t.dmax-t.dmin)/2}t.uncertain_to_width=(t.dmax-e)*this.pixelsPerMillisecond}return t.top=this.top+this.availableHeight-(t.row+1)*r.EVENT_ROW_HEIGHT+this.offsetY,t.color=this.getColor(t.from,t.to),t})}update(){super.update(),this.updateEvents()}getEventByCoordinates(t,e){const i=this.timestampAtPosition(t),n=a.default.viewportOffset+this.top+this.availableHeight+this.offsetY,s=Math.floor((n-e)/r.EVENT_ROW_HEIGHT);return this.events.find(t=>!(!(t.from<i&&t.screenTo>i)||t.row<this.lowestVisibleRow||t.row>this.highestVisibleRow)&&t.row===s)}zoomIn(){o.default.zoomTo(this,this.zoomLevel+1)}zoomOut(){o.default.zoomTo(this,this.zoomLevel-1)}}}])}); |
@@ -19,3 +19,4 @@ [ | ||
"label": "Vasco da Gama", | ||
"date": -16094073600000, | ||
"date_min": -16094073600000, | ||
"date": -15809990400000, | ||
"end_date": -14043542400000 | ||
@@ -22,0 +23,0 @@ }, |
[ | ||
{ | ||
"label": "Plato", | ||
"date": -75673612800000, | ||
"end_date": -73085932800000 | ||
"lbl": "Plato", | ||
"dmin": -75673612800000, | ||
"d": -75484224000001, | ||
"ed": -73149004800000, | ||
"dmax": -73085846400001 | ||
}, | ||
{ | ||
"label": "Confucius", | ||
"date": -79555046400000, | ||
"end_date": -77251536000000 | ||
"lbl": "Confucius", | ||
"d": -79555046400000, | ||
"ed": -77251536000000 | ||
}, | ||
{ | ||
"label": "Aristotle", | ||
"date": -74285078400000, | ||
"end_date": -72297014400000 | ||
"lbl": "Aristotle", | ||
"d": -74285078400000, | ||
"ed": -72297014400000 | ||
}, | ||
{ | ||
"label": "Alexander the Great", | ||
"date": -73384099200000, | ||
"end_date": -72346089600000 | ||
"lbl": "Alexander the Great", | ||
"d": -73384099200000, | ||
"ed": -72346089600000 | ||
}, | ||
{ | ||
"label": "Socrates", | ||
"date": -76998988800000, | ||
"end_date": -74726928000000 | ||
"lbl": "Socrates", | ||
"d": -76998988800000, | ||
"ed": -74726928000000 | ||
}, | ||
{ | ||
"label": "Cicero", | ||
"date": -65512022400000, | ||
"end_date": -63494755200000 | ||
"lbl": "Cicero", | ||
"d": -65512022400000, | ||
"ed": -63494755200000 | ||
}, | ||
{ | ||
"label": "Augustine of Hippo", | ||
"date": -50968742400000, | ||
"end_date": -48577017600000 | ||
"lbl": "Augustine of Hippo", | ||
"d": -50968742400000, | ||
"ed": -48577017600000 | ||
}, | ||
{ | ||
"label": "Thomas Aquinas", | ||
"date": -23509872000000, | ||
"end_date": -21957955200000 | ||
"lbl": "Thomas Aquinas", | ||
"dmin": -23509872000000, | ||
"d": -23478336000001, | ||
"ed": -21957955200000 | ||
}, | ||
{ | ||
"label": "Ibn Khaldun", | ||
"date": -20120659200000, | ||
"end_date": -17791660800000 | ||
"lbl": "Ibn Khaldun", | ||
"d": -20120659200000, | ||
"ed": -17791660800000 | ||
}, | ||
{ | ||
"label": "Avicenna", | ||
"date": -31221158400000, | ||
"end_date": -29427840000000 | ||
"lbl": "Avicenna", | ||
"d": -31221158400000, | ||
"ed": -29427840000000 | ||
}, | ||
{ | ||
"label": "Magna Carta", | ||
"date": -23811235200000 | ||
"lbl": "Magna Carta", | ||
"d": -23811235200000 | ||
}, | ||
{ | ||
"label": "Niccolò Machiavelli", | ||
"date": -15799449600000, | ||
"end_date": -13965004800000 | ||
"lbl": "Niccolò Machiavelli", | ||
"d": -15799449600000, | ||
"ed": -13965004800000 | ||
}, | ||
{ | ||
"label": "Jean-Jacques Rousseau", | ||
"date": -8126265600000, | ||
"end_date": -6043161600000 | ||
"lbl": "Jean-Jacques Rousseau", | ||
"d": -8126265600000, | ||
"ed": -6043161600000 | ||
}, | ||
{ | ||
"label": "Thomas Hobbes", | ||
"date": -12046579200000, | ||
"end_date": -9153907200000 | ||
"lbl": "Thomas Hobbes", | ||
"d": -12046579200000, | ||
"ed": -9153907200000 | ||
}, | ||
{ | ||
"label": "John Locke", | ||
"date": -10645430400000, | ||
"end_date": -8368185600000 | ||
"lbl": "John Locke", | ||
"d": -10645430400000, | ||
"ed": -8368185600000 | ||
}, | ||
{ | ||
"label": "Montesquieu", | ||
"date": -8865936000000, | ||
"end_date": -6781276800000 | ||
"lbl": "Montesquieu", | ||
"d": -8865936000000, | ||
"ed": -6781276800000 | ||
}, | ||
{ | ||
"label": "Voltaire", | ||
"date": -8681644800000, | ||
"end_date": -6046012800000 | ||
"lbl": "Voltaire", | ||
"d": -8681644800000, | ||
"ed": -6046012800000 | ||
}, | ||
{ | ||
"label": "Karl Marx", | ||
"date": -4785955200000, | ||
"end_date": -2739225600000 | ||
"lbl": "Karl Marx", | ||
"d": -4785955200000, | ||
"ed": -2739225600000, | ||
"img": "jpg", | ||
"wid": "Q9061" | ||
}, | ||
{ | ||
"label": "Friedrich Engels", | ||
"date": -4704912000000, | ||
"end_date": -2348092800000 | ||
"lbl": "Friedrich Engels", | ||
"d": -4704912000000, | ||
"ed": -2348092800000 | ||
}, | ||
{ | ||
"label": "John Rawls", | ||
"date": -1541894400000, | ||
"end_date": 1038096000000 | ||
"lbl": "John Rawls", | ||
"d": -1541894400000, | ||
"ed": 1038096000000, | ||
"img": "jpg", | ||
"wid": "Q172544" | ||
}, | ||
{ | ||
"label": "Jeremy Bentham", | ||
"date": -7001769600000, | ||
"end_date": -4341340800000 | ||
"lbl": "Jeremy Bentham", | ||
"d": -7001769600000, | ||
"ed": -4341340800000 | ||
}, | ||
{ | ||
"label": "Michel Foucault", | ||
"date": -1363737600000, | ||
"end_date": 456969600000 | ||
"lbl": "Michel Foucault", | ||
"d": -1363737600000, | ||
"ed": 456969600000, | ||
"img": "jpg", | ||
"wid": "Q44272" | ||
}, | ||
{ | ||
"label": "David Hume", | ||
"date": -8162380800000, | ||
"end_date": -6101568000000 | ||
"lbl": "David Hume", | ||
"d": -8162380800000, | ||
"ed": -6101568000000 | ||
}, | ||
{ | ||
"label": "Thomas Jefferson", | ||
"date": -7154611200000, | ||
"end_date": -4528310400000 | ||
"lbl": "Thomas Jefferson", | ||
"d": -7154611200000, | ||
"ed": -4528310400000 | ||
}, | ||
{ | ||
"label": "Immanuel Kant", | ||
"date": -7753363200000, | ||
"end_date": -5234889600000 | ||
"lbl": "Immanuel Kant", | ||
"d": -7753363200000, | ||
"ed": -5234889600000, | ||
"img": "jpg", | ||
"wid": "Q9312" | ||
}, | ||
{ | ||
"label": "Peter Kropotkin", | ||
"date": -4009737600000, | ||
"end_date": -1543017600000 | ||
"lbl": "Peter Kropotkin", | ||
"d": -4009737600000, | ||
"ed": -1543017600000, | ||
"img": "jpg", | ||
"wid": "Q5752" | ||
}, | ||
{ | ||
"label": "John Stuart Mill", | ||
"date": -5163350400000, | ||
"end_date": -3050006400000 | ||
"lbl": "John Stuart Mill", | ||
"d": -5163350400000, | ||
"ed": -3050006400000 | ||
} | ||
] |
{ | ||
"name": "timeline", | ||
"version": "3.2.2", | ||
"version": "3.3.0", | ||
"description": "", | ||
@@ -19,13 +19,13 @@ "main": "build/index.js", | ||
"devDependencies": { | ||
"@types/jest": "^23.3.1", | ||
"jest": "^23.5.0", | ||
"@types/jest": "^23.3.2", | ||
"jest": "^23.6.0", | ||
"pg": "^7.4.3", | ||
"ts-jest": "^23.1.4", | ||
"ts-loader": "^4.5.0", | ||
"ts-jest": "^23.10.1", | ||
"ts-loader": "^5.1.1", | ||
"tslib": "^1.9.3", | ||
"typescript": "^3.0.1", | ||
"uglifyjs-webpack-plugin": "^1.3.0", | ||
"webpack": "^4.17.1", | ||
"typescript": "^3.0.3", | ||
"uglifyjs-webpack-plugin": "^2.0.1", | ||
"webpack": "^4.19.1", | ||
"webpack-cli": "^3.1.0", | ||
"webpack-dev-server": "^3.1.5" | ||
"webpack-dev-server": "^3.1.8" | ||
}, | ||
@@ -32,0 +32,0 @@ "jest": { |
import props from "./models/props"; | ||
import { Milliseconds, ZOOM_DONE, CENTER_CHANGE_DONE } from "./constants"; | ||
import { Milliseconds, EventType } from "./constants"; | ||
import Band from "./models/band"; | ||
@@ -8,2 +8,4 @@ import Canvas from "./views/canvas"; | ||
import EventsBand from "./models/band/events"; | ||
import Popup from './views/popup'; | ||
import eventBus from './event-bus'; | ||
@@ -46,3 +48,3 @@ export type Multiplier = .25 | .5 | 1 | 2 | 4 | 8 | 16 | ||
private models: Band<MinimapBandConfig | EventsBandConfig>[] = [] | ||
private views: (Canvas | Debug)[] = [] | ||
private views: (Canvas | Debug | Popup)[] = [] | ||
@@ -55,3 +57,3 @@ private zoomMarker: number | ||
registerView(view: Canvas | Debug) { | ||
registerView(view: Canvas | Debug | Popup) { | ||
this.views.push(view) | ||
@@ -107,3 +109,3 @@ } | ||
this.adjustMinimapBands() | ||
document.dispatchEvent(new CustomEvent(ZOOM_DONE)) | ||
eventBus.dispatch(EventType.ZoomDone) | ||
this.stop() | ||
@@ -143,3 +145,3 @@ } | ||
this.elapsedTimeTotal = 0 | ||
document.dispatchEvent(new CustomEvent(CENTER_CHANGE_DONE)) | ||
eventBus.dispatch(EventType.CenterChange) | ||
} | ||
@@ -215,2 +217,3 @@ | ||
playForward() { | ||
eventBus.dispatch(EventType.Play) | ||
this.direction = Direction.Forward | ||
@@ -221,2 +224,3 @@ this.nextFrame() | ||
playBackward() { | ||
eventBus.dispatch(EventType.Play) | ||
this.direction = Direction.Backward | ||
@@ -227,2 +231,3 @@ this.nextFrame() | ||
stop() { | ||
eventBus.dispatch(EventType.Pause) | ||
this.direction = Direction.Stop | ||
@@ -229,0 +234,0 @@ this.activeBand = null |
import animator, { Animator } from './animator' | ||
import { CENTER_CHANGE_DONE, ZOOM_DONE } from './constants' | ||
import props, { Props } from './models/props' | ||
import View from './views'; | ||
import { EventType } from './constants'; | ||
@@ -12,3 +12,3 @@ export type OnChangeFunction = (props: Props, e?: Event) => void | ||
constructor(private onChange: OnChangeFunction) { | ||
constructor() { | ||
document.addEventListener('keydown', (ev) => { | ||
@@ -19,12 +19,32 @@ if (ev.keyCode === 189) props.controlBand.zoomOut() // - | ||
if (this.onChange != null && typeof this.onChange === 'function') { | ||
document.addEventListener(CENTER_CHANGE_DONE, this.handleChange) | ||
document.addEventListener(ZOOM_DONE, this.handleChange) | ||
} | ||
// if (this.onChange != null && typeof this.onChange === 'function') { | ||
// document.addEventListener(EventType.CENTER_CHANGE_DONE, this.handleChange) | ||
// document.addEventListener(EventType.ZOOM_DONE, this.handleChange) | ||
// } | ||
} | ||
private handleChange = () => { | ||
this.onChange(props) | ||
on(eventName: string, func: any) { | ||
const nameMap = { | ||
centerchange: EventType.CenterChange, | ||
pause: EventType.Pause, | ||
play: EventType.Play, | ||
scrolldone: EventType.ScrollDone, | ||
select: EventType.Select, | ||
zoomdone: EventType.ZoomDone, | ||
} | ||
if (Object.keys(nameMap).indexOf(eventName) > -1) { | ||
const eventType = (nameMap as any)[eventName] | ||
let realFunc | ||
if (eventType === EventType.CenterChange) realFunc = () => func(props) | ||
else if (eventType === EventType.Select) realFunc = (ev: any) => func(ev.detail) | ||
else realFunc = func | ||
document.addEventListener(eventType, realFunc) | ||
} | ||
} | ||
// private handleChange = () => { | ||
// this.onChange(props) | ||
// } | ||
protected resize = () => { | ||
@@ -31,0 +51,0 @@ props.resize() |
import { RawEv3nt } from "./models/event"; | ||
export const EVENT_HEIGHT = 14 | ||
export const IMAGE_SIZES = [16, 32, 64, 128, 256] | ||
// The height of an event. This is best seen by the height of an interval | ||
export const EVENT_HEIGHT = 16 | ||
// Function for letter width is lineair: letter_width(event_height) = 7.5/40 * event_height + 3.5 | ||
// - font size = 72 => letter width = 17 | ||
// - font size = 48 => letter width = 12.5 | ||
// - font size = 32 => letter width = 9.5 | ||
export const LETTER_WIDTH = Math.round(EVENT_HEIGHT * .1875 + 3.5) | ||
// Function for font size is lineair: font_size(event_height) = 5/16 * event_height + 6 | ||
// Taken from two points: | ||
// - event height = 16 => font size = 11 | ||
// - event height = 32 => font size = 16 | ||
export const FONT_SIZE = Math.round(EVENT_HEIGHT * .3125 + 6) | ||
// The vertical space between two events. This is best seen between two intervals | ||
export const ROW_SPACING = Math.round(EVENT_HEIGHT / 3) | ||
// The height (in px) of a row of events. | ||
export const EVENT_ROW_HEIGHT = 16 | ||
export const EVENT_ROW_HEIGHT = EVENT_HEIGHT + ROW_SPACING | ||
export const DATE_BAR_HEIGHT = EVENT_ROW_HEIGHT | ||
export const RULER_LABELS_HEIGHT = 60 | ||
export const CENTER_CHANGE_DONE = 'CENTER_CHANGE_DONE' | ||
export const ZOOM_DONE = 'ZOOM_DONE' | ||
export const SCROLL_DONE = 'SCROLL_DONE' | ||
// The bounding box is the box where the image must fit within. | ||
// In this case the image should not be higher or wider than | ||
// 2 times the event row height | ||
export const IMAGE_BOUNDING_BOX = (EVENT_ROW_HEIGHT * 2) - ROW_SPACING * 2 | ||
export const IMAGE_BORDER_SIZE = Math.round(ROW_SPACING / 2) | ||
export const IMAGE_SIZE = IMAGE_SIZES.reduce((prev, curr) => Math.abs(curr - IMAGE_BOUNDING_BOX) < Math.abs(prev - IMAGE_BOUNDING_BOX) ? curr : prev) | ||
export enum EventType { | ||
CenterChange = 'CenterChange', | ||
ZoomDone = 'ZoomDone', | ||
ScrollDone = 'ScrollDone', | ||
Pause = 'Pause', | ||
Play = 'Play', | ||
Select = 'Select' | ||
} | ||
export const PIXELS_PER_LETTER = 8 | ||
export const DEFAULT_IMAGE_PATH = '/images' | ||
export type Milliseconds = number | ||
@@ -37,2 +67,2 @@ export type Grid = [Milliseconds, Milliseconds][][] | ||
'rgba(0,128,0' | ||
].map(color => (opacity: number = 1) => `${color},${opacity})`) | ||
].map(color => (opacity: number = 1) => `${color},${opacity})`) |
@@ -0,1 +1,3 @@ | ||
import { EventType } from './constants'; | ||
type EventListener = [string, EventListenerOrEventListenerObject, Target] | ||
@@ -13,2 +15,10 @@ export type Target = Document | Window | HTMLElement | ||
dispatch(eventType: EventType, payload?: any) { | ||
const event = (payload != null) ? | ||
new CustomEvent(eventType, { detail: payload }) : | ||
new CustomEvent(eventType) | ||
document.dispatchEvent(event) | ||
} | ||
register(type: string, listener: EventListenerOrEventListenerObject, target: Target = document) { | ||
@@ -15,0 +25,0 @@ target.addEventListener(type, listener) |
@@ -6,4 +6,4 @@ import props, { Props } from './models/props' | ||
import { debounce, calcPixelsPerMillisecond } from './utils' | ||
import { OrderedEvents, orderEvents } from './utils/events.worker' | ||
import Api, { OnChangeFunction } from './api' | ||
import { OrderedTimeline, orderEvents } from './utils/events.worker' | ||
import Api from './api' | ||
import EventsBandView from './views/band/events' | ||
@@ -13,7 +13,9 @@ import Canvas from './views/canvas' | ||
import Label from './views/label' | ||
import Popup from './views/popup' | ||
import MinimapBand from './models/band/minimap' | ||
import EventsBand from './models/band/events' | ||
import { formatDate } from './utils/dates'; | ||
import { RawEv3nt } from './models/event'; | ||
import { BandType } from './models/band'; | ||
import { formatDate } from './utils/dates' | ||
import { Ev3ntLocation, RawEv3nt, Ev3nt, Voyage } from './models/event' | ||
import { BandType } from './models/band' | ||
import { EventType } from './constants'; | ||
// import Debug from './views/debug' | ||
@@ -23,23 +25,27 @@ | ||
Config as TimelineConfig, | ||
Props as TimelineProps, | ||
Ev3nt, | ||
Ev3ntLocation, | ||
EventsBand, | ||
EventType, | ||
MinimapBand, | ||
OrderedEvents, | ||
OrderedTimeline, | ||
Props as TimelineProps, | ||
RawEv3nt, | ||
calcPixelsPerMillisecond, | ||
formatDate, | ||
orderEvents, | ||
RawEv3nt | ||
Voyage, | ||
} | ||
export type OnSelectFunction = (e: RawEv3nt) => void | ||
export type OnSelectFunction = (e: Ev3nt, band: EventsBand, props: Props) => void | ||
// FIXME top row is visible when vertical scrolling (see Halicarnassus) | ||
// FIX config without events | ||
// TODO sort intervals first and than the points in time on top | ||
// TODO use available vertical space (not fixed to EVENT_HEIGHT), see examples/100m | ||
// TODO expose only API, put the Timeline and it's render in a separate view | ||
// TODO add async loading of events | ||
// TODO add API to constrain by spacial data | ||
// TODO Add open ranges (ie: people still alive) and EDTF dates | ||
// TODO Add open ranges (ie: people still alive) | ||
// TODO If event granularity is equal to band granularity a point in time should be rendered as an interval (as unsure?) | ||
// TODO flip PiT when on edge of timeline | ||
// TODO make it possible to have only minimap bands (see examples/floods) | ||
// TODO use available vertical space (not fixed to EVENT_HEIGHT), see examples/100m | ||
// TODO add context menu for settings (which bands to show, toggle hor/ver scroll, change colors) | ||
@@ -51,7 +57,13 @@ // TODO add info about how many events below and above current view (show after scroll and hide after x seconds) | ||
// TODO make option for fixed minimap, no zoom when events band get's zoomed | ||
// interface Options { | ||
// config: Config, | ||
// onSelect?: OnSelectFunction | ||
// } | ||
export default class Timeline extends Api { | ||
private wrapper: HTMLElement | ||
private wrapper: HTMLDivElement | ||
private popup: Popup | ||
constructor(protected config: Config, onChange?: OnChangeFunction, private onSelect?: OnSelectFunction) { | ||
super(onChange) | ||
// constructor(protected config: Config, onChange?: OnChangeFunction, private onSelect?: OnSelectFunction) { | ||
constructor(config: Config) { | ||
super() | ||
@@ -61,2 +73,4 @@ props.init(config) | ||
this.popup = new Popup(this.wrapper) | ||
const debouncedResize = debounce(this.resize, 600) | ||
@@ -66,2 +80,10 @@ window.addEventListener('resize', debouncedResize) | ||
hidePopup() { | ||
this.popup.hide() | ||
} | ||
showPopup(event: Ev3nt) { | ||
this.popup.show(event) | ||
} | ||
private render() { | ||
@@ -85,3 +107,3 @@ this.wrapper = createElement( | ||
band.type === BandType.EventsBand ? | ||
new EventsBandView(band as EventsBand, this.onSelect) : | ||
new EventsBandView(band as EventsBand) : | ||
new BandView(band) | ||
@@ -88,0 +110,0 @@ ) |
@@ -6,6 +6,5 @@ import Band, { BandType } from '.' | ||
import props from '../props' | ||
import { RawEv3nt } from '../event' | ||
import { orderEvents } from '../../utils/events.worker'; | ||
import { byDate } from '../../utils/dates'; | ||
import { calcPixelsPerMillisecond } from '../../utils'; | ||
import { Ev3nt } from '../event' | ||
import { OrderedBand } from '../../utils/events.worker' | ||
import { byDate } from '../../utils/dates' | ||
@@ -21,5 +20,5 @@ export default class EventsBand extends Band<EventsBandConfig> { | ||
events: RawEv3nt[] = [] | ||
events: Ev3nt[] = [] | ||
rowCount: number = 0 | ||
visibleEvents: RawEv3nt[] = [] | ||
visibleEvents: Ev3nt[] = [] | ||
@@ -50,11 +49,7 @@ private _offsetY: Pixels = 0 | ||
init() { | ||
init(orderedBand: OrderedBand) { | ||
super.init() | ||
const pixelsPerMillisecond = calcPixelsPerMillisecond(props.viewportWidth, this.config.zoomLevel || 0, props.time) | ||
const orderedEvents = this.config.orderedEvents == null ? | ||
orderEvents(this.config.events, pixelsPerMillisecond) : | ||
this.config.orderedEvents | ||
this.events = orderedEvents.events | ||
this.rowCount = orderedEvents.row_count | ||
this.events = orderedBand.events | ||
this.rowCount = orderedBand.rowCount | ||
@@ -108,2 +103,3 @@ this.height = EVENT_ROW_HEIGHT * this.rowCount | ||
// event.width (px) === event.time (ms) | ||
@@ -113,5 +109,36 @@ event.width = Math.round((event.time) * this.pixelsPerMillisecond) // || [<- width ->] || | ||
// event.padding (px) === event.space (ms) | ||
event.padding = Math.round((event.space) * this.pixelsPerMillisecond) // || [ event ]<- padding -> || | ||
event.uncertain_from_width = 0 | ||
if (event.dmin != null) { | ||
let uncertain_from_to | ||
if (event.d != null) { | ||
uncertain_from_to = event.d | ||
} | ||
else if (event.ed != null) { | ||
uncertain_from_to = event.ed | ||
} else if (event.dmax != null) { | ||
uncertain_from_to = event.dmin + (event.dmax - event.dmin) / 2 | ||
} else { | ||
throw Error(['updateEvents', 'Width uncertain from is not definable', JSON.stringify(event)].join('\n')) | ||
} | ||
event.uncertain_from_width = (uncertain_from_to - event.dmin) * this.pixelsPerMillisecond | ||
} | ||
event.uncertain_to_width = 0 | ||
if (event.dmax != null) { | ||
let uncertain_to_from | ||
if (event.ed != null) { | ||
uncertain_to_from = event.ed | ||
} | ||
else if (event.d != null) { | ||
uncertain_to_from = event.d | ||
} else if (event.dmin != null) { | ||
uncertain_to_from = event.dmin + (event.dmax - event.dmin) / 2 | ||
} else { | ||
throw Error(['updateEvents', 'Width uncertain to is not definable', JSON.stringify(event)].join('\n')) | ||
} | ||
event.uncertain_to_width = (event.dmax - uncertain_to_from) * this.pixelsPerMillisecond | ||
} | ||
event.top = this.top + this.availableHeight - ((event.row + 1) * EVENT_ROW_HEIGHT) + this.offsetY | ||
@@ -130,3 +157,3 @@ | ||
getEventByCoordinates(x: Pixels, y: Pixels): RawEv3nt { | ||
getEventByCoordinates(x: Pixels, y: Pixels): Ev3nt { | ||
const timestamp = this.timestampAtPosition(x) | ||
@@ -139,3 +166,3 @@ | ||
if ( | ||
!(e.from < timestamp && e.from + e.time + e.space > timestamp) || | ||
!(e.from < timestamp && e.screenTo > timestamp) || | ||
(e.row < this.lowestVisibleRow || e.row > this.highestVisibleRow) | ||
@@ -150,2 +177,6 @@ ) return false | ||
// orderEvents() { | ||
// orderEvents(this.events, this.pixelsPerMillisecond) | ||
// } | ||
zoomIn() { | ||
@@ -152,0 +183,0 @@ animator.zoomTo(this, this.zoomLevel + 1) |
@@ -7,2 +7,3 @@ import { getGranularity, Granularity, subsequentDate } from '../../utils/dates' | ||
import animator from '../../animator'; | ||
import { OrderedBand } from '../../utils/events.worker'; | ||
@@ -48,4 +49,4 @@ export enum BandType { | ||
// The amount of pixels taken by one day. Metric used for calculating | ||
// the x-position of an event or ruler on the timeline. | ||
// The amount of pixels taken by one millisecond. Metric used to convert | ||
// milliseconds to pixels and vice versa (px = ms / ppm and ms = px * ppm) | ||
pixelsPerMillisecond: Pixels | ||
@@ -90,2 +91,3 @@ | ||
this.availableHeight = this.visibleHeight - DATE_BAR_HEIGHT | ||
if (this.availableHeight / this.visibleHeight < .666) this.availableHeight = this.visibleHeight * .666 | ||
this.visibleRowsCount = Math.floor(this.availableHeight / EVENT_ROW_HEIGHT) - 1 | ||
@@ -101,3 +103,3 @@ this.top = Math.round(this.config.topOffsetRatio * props.viewportHeight) | ||
init() { | ||
init(_orderedBand?: OrderedBand): void { | ||
this.zoomLevel = this.config.zoomLevel | ||
@@ -104,0 +106,0 @@ this.setVerticalProps() |
@@ -81,12 +81,17 @@ import Band, { BandType } from '.' | ||
if (event.from > to || event.to < from) continue | ||
const x = this.positionAtTimestamp(event.from) | ||
const y = this.maxRowCount - ((event.row + 2) * this.eventHeight) | ||
const eventWidth = Math.round(event.time * this.pixelsPerMillisecond) | ||
const eventLeft = this.positionAtTimestamp(event.date_min != null ? event.date_min : event.date) | ||
const y = this.maxRowCount - ((event.row + 1) * this.eventHeight) | ||
const width = eventWidth < 1 ? 1 : eventWidth | ||
this.nextCtx.rect(eventLeft, y, width, this.eventHeight) | ||
this.nextCtx.fillStyle = `rgb(190, 190, 190)` | ||
this.nextCtx.fillRect(x, y, width, this.eventHeight) | ||
if (event.img) { | ||
this.nextCtx.fillStyle = `rgb(240, 240, 240)` | ||
this.nextCtx.fillRect(x, y - this.eventHeight * 2, this.eventHeight * 2, this.eventHeight * 2) | ||
} | ||
} | ||
}) | ||
this.nextCtx.fillStyle = `rgb(190, 190, 190)` | ||
this.nextCtx.fill() | ||
} | ||
@@ -93,0 +98,0 @@ |
import { Ratio } from "../../constants" | ||
import { OrderedEvents } from "../../utils/events.worker" | ||
import { RawEv3nt } from "../event" | ||
import { OrderedTimeline } from "../../utils/events.worker" | ||
import { RawEv3nt, Ev3nt } from "../event" | ||
import MinimapBand from "../band/minimap" | ||
@@ -42,12 +42,16 @@ import EventsBand from "../band/events" | ||
label?: string | ||
orderedEvents?: OrderedEvents | ||
orderedEvents?: OrderedTimeline | ||
} | ||
export default class Config { | ||
bands: (EventsBand | MinimapBand)[] | ||
center?: number | ||
controlBand: EventsBand | ||
controlBand?: EventsBand | ||
bands: (EventsBand | MinimapBand)[] | ||
imagePath?: string | ||
parent?: Ev3nt | ||
// The HTML element where the Timeline will be attached to. The element should be a | ||
@@ -54,0 +58,0 @@ // block element with a width and height. |
@@ -1,67 +0,103 @@ | ||
import { Milliseconds, Pixels } from '../constants'; | ||
import { Milliseconds, Pixels, PIXELS_PER_LETTER, EVENT_HEIGHT } from '../constants'; | ||
import { Granularity } from '../utils/dates'; | ||
// import Band from './band'; | ||
export enum ImageFileType { | ||
NONE = 'none', | ||
JPG = 'jpg', | ||
SVG = 'svg', | ||
GIF = 'gif', | ||
PNG = 'png', | ||
} | ||
class Point { | ||
type: "Point" | ||
coordinates: [number, number] | ||
} | ||
export class Ev3ntLocation { | ||
coor: Point | ||
coor4326?: [number, number] | ||
dmin?: Milliseconds | ||
dmin_g?: Granularity | ||
d?: Milliseconds | ||
d_g?: Granularity | ||
ed?: Milliseconds | ||
ed_g?: Granularity | ||
dmax?: Milliseconds | ||
dmax_g?: Granularity | ||
} | ||
export class Voyage { | ||
d: Milliseconds | ||
ed: Milliseconds | ||
route: string | ||
sp?: Point // Start point | ||
ep?: Point // End point | ||
} | ||
export class RawEv3nt { | ||
date: Milliseconds | ||
date_granularity?: Granularity = Granularity.DAY | ||
date_min?: Milliseconds | ||
date_min_granularity?: Granularity | ||
description?: string | ||
end_date?: Milliseconds | ||
end_date_granularity?: Granularity | ||
end_date_max?: Milliseconds | ||
end_date_max_granularity?: Granularity | ||
id?: string | ||
label?: string | ||
row?: number | ||
wikidata_identifier?: string | ||
class: string[] | ||
d: Milliseconds | ||
d_g: Granularity | ||
dmax: Milliseconds | ||
dmax_g: Granularity | ||
dmin: Milliseconds | ||
dmin_g: Granularity | ||
dsc: string | ||
ed: Milliseconds | ||
ed_g: Granularity | ||
id: string | ||
img: ImageFileType | ||
lbl: string | ||
locs: Ev3ntLocation[] | ||
voyages: Voyage[] | ||
wid: string | ||
} | ||
export class Ev3nt extends RawEv3nt { | ||
from: Milliseconds | ||
to: Milliseconds | ||
screenTo: Milliseconds | ||
tags: string[] | ||
locations: any[] | ||
// The length of time an event took. | ||
// A Point in Time has time = 0 | ||
// For an interval, if something takes 1 year, time = 31536000000 | ||
// For an interval, if the event takes 1 year, time = 31536000000 | ||
time?: Milliseconds | ||
// The space an event needs for display | ||
// Point in Time = label width + padding | ||
// Interval = padding | ||
space?: Milliseconds | ||
row: number | ||
/* runtime */ | ||
// Same as from, to, screenTo and time as in: they all just need the pixelsPerMS var to be calc'd? | ||
left?: Pixels | ||
padding?: Pixels | ||
top?: Pixels | ||
width?: Pixels | ||
uncertain_from_width?: Pixels | ||
uncertain_to_width?: Pixels | ||
color?: string | ||
// textWidth?: Pixels | ||
} | ||
image?: HTMLImageElement | ||
/* runtime */ | ||
// class Ev3nt extends RawEv3nt { | ||
// left: Pixels | ||
// width: Pixels | ||
constructor(event: RawEv3nt, pixelsPerMillisecond?: Pixels) { | ||
super() | ||
// constructor(rawEvent: RawEv3nt, band: Band) { | ||
// super() | ||
for (const key in event) { | ||
if ((event as any)[key] != null) (this as any)[key] = (event as any)[key] | ||
} | ||
// Object.keys(rawEvent).forEach(k => this[k] = rawEvent[k]) | ||
if (this.lbl == null) this.lbl = 'NO LABEL' | ||
if (this.id == null) this.id = 'id_' + crypto.getRandomValues(new Uint8Array(4)).join('_') | ||
// this.left = band.positionAtDate(this.date) | ||
// this.width = this.isInterval() ? | ||
// (this.end_date - this.date) * band.pixelsPerMillisecond : | ||
// 0 | ||
// this.row = rawEvent.row | ||
// // this.flip = this.left + Constants.EVENT_MIN_SPACE > visibleDomain.width | ||
// } | ||
this.from = this.dmin || this.d | ||
this.to = this.dmax || this.ed | ||
if (this.to == null) this.to = this.from | ||
this.time = this.to - this.from | ||
// isInterval(): boolean { | ||
// return this.end_date != null | ||
// } | ||
// } | ||
// export default Ev3nt; | ||
if (pixelsPerMillisecond != null) { | ||
const paddingRight = Math.round(EVENT_HEIGHT * 2 / pixelsPerMillisecond) | ||
let space = ((this.lbl.length * PIXELS_PER_LETTER) / pixelsPerMillisecond) + paddingRight | ||
space = space > this.time ? space - this.time : 0 | ||
this.screenTo = Math.round(this.from + this.time + space) | ||
} | ||
} | ||
} |
@@ -1,7 +0,9 @@ | ||
import { CENTER_CHANGE_DONE, Milliseconds, Pixels } from "../constants" | ||
import { Milliseconds, Pixels, DEFAULT_IMAGE_PATH, EventType } from "../constants" | ||
import Config from "./config" | ||
import MinimapBand from "./band/minimap" | ||
import { debounce } from "../utils" | ||
import EventsBand from "./band/events"; | ||
import { BandType } from './band'; | ||
import EventsBand from "./band/events" | ||
import { BandType } from './band' | ||
import { RawEv3nt } from './event'; | ||
import { orderEvents } from '..'; | ||
import eventBus from '../event-bus'; | ||
@@ -19,2 +21,4 @@ function onEventsBand (band: MinimapBand | EventsBand): band is EventsBand { | ||
parent: RawEv3nt | ||
bands: (EventsBand | MinimapBand)[] | ||
@@ -26,2 +30,4 @@ eventsBands: EventsBand[] | ||
imagePath: string | ||
// Timestamp of the start date of the timeline | ||
@@ -50,3 +56,3 @@ from: Milliseconds | ||
else this._center = n | ||
this.centerChangeDone() | ||
eventBus.dispatch(EventType.CenterChange) | ||
} | ||
@@ -62,28 +68,32 @@ | ||
private centerChangeDone = debounce(() => { | ||
document.dispatchEvent(new CustomEvent(CENTER_CHANGE_DONE)) | ||
}, 300) | ||
init(config: Config) { | ||
if (config.rootElement == null) console.error('[init] No rootElement found') | ||
this.imagePath = config.imagePath != null ? config.imagePath : DEFAULT_IMAGE_PATH | ||
this.rootElement = config.rootElement | ||
this.dimensions = this.rootElement | ||
const [froms, tos] = config.bands.reduce((prev, curr) => { | ||
if (curr.type === BandType.MinimapBand) return prev | ||
const band = curr as EventsBand | ||
const events = band.config.orderedEvents == null ? band.config.events : band.config.orderedEvents.events | ||
prev[0].push(events[0].date_min || events[0].date) | ||
prev[1].push(events.reduce((prev2, curr2) => { | ||
return Math.max(prev2, curr2.end_date || -Infinity, curr2.end_date_max || -Infinity) | ||
}, -Infinity)) | ||
return prev | ||
}, [[], []]) | ||
this.bands = config.bands | ||
this.eventsBands = this.bands.filter(onEventsBand) | ||
this.minimapBands = this.bands.filter(onMinimapBand) | ||
this.controlBand = config.controlBand != null ? config.controlBand : this.eventsBands[0] | ||
this.from = Math.min(...froms) | ||
this.to = Math.max(...tos) | ||
const t0 = performance.now() | ||
const options = { | ||
bands: this.eventsBands | ||
.map(band => ({ | ||
events: band.config.events, | ||
zoomLevel: band.config.zoomLevel | ||
})), | ||
parent: config.parent, | ||
viewportWidth: this.viewportWidth | ||
} | ||
const orderResult = orderEvents(options) | ||
this.parent = orderResult.parent | ||
this.from = orderResult.from | ||
this.to = orderResult.to | ||
this.time = orderResult.time | ||
const t1 = performance.now(); | ||
console.log('Performance: ', `${t1 - t0}ms\n[from] ${new Date(this.from).toUTCString()}\n[ to ] ${new Date(this.to).toUTCString()}`) | ||
this.time = this.to - this.from | ||
this.center = (config.center != null) ? | ||
@@ -93,8 +103,7 @@ config.center : | ||
this.bands = config.bands | ||
this.eventsBands = this.bands.filter(onEventsBand) | ||
this.minimapBands = this.bands.filter(onMinimapBand) | ||
this.controlBand = config.controlBand != null ? config.controlBand : this.eventsBands[0] | ||
for (const [index, band] of this.eventsBands.entries()) { | ||
band.init(orderResult.bands[index]) | ||
} | ||
for (const band of this.bands) { | ||
for (const band of this.minimapBands) { | ||
band.init() | ||
@@ -101,0 +110,0 @@ } |
@@ -15,3 +15,3 @@ import { Milliseconds, Pixels } from "../constants" | ||
WEEK = "WEEK", | ||
MONTH = "MONHT", | ||
MONTH = "MONTH", | ||
YEAR = "YEAR", | ||
@@ -100,3 +100,3 @@ YEAR_5 = "YEAR_5", /* 5 YEARS */ | ||
if (pixelsPerMillisecond > 8e-11) return Granularity.DECADE_5 | ||
if (pixelsPerMillisecond > 1e-11) return Granularity.CENTURY | ||
if (pixelsPerMillisecond > 1.5e-11) return Granularity.CENTURY | ||
if (pixelsPerMillisecond > 5e-12) return Granularity.CENTURY_5 | ||
@@ -198,9 +198,9 @@ return Granularity.MILLENIUM | ||
export function byDate(a: RawEv3nt, b: RawEv3nt) { | ||
const aFrom = a.date_min != null ? a.date_min : a.date | ||
const bFrom = b.date_min != null ? b.date_min : b.date | ||
const aFrom = a.dmin != null ? a.dmin : a.d | ||
const bFrom = b.dmin != null ? b.dmin : b.d | ||
if (aFrom < bFrom) return -1 | ||
if (aFrom > bFrom) return 1 | ||
const aTo = a.end_date_max != null ? a.end_date_max : a.end_date | ||
const bTo = b.end_date_max != null ? b.end_date_max : b.end_date | ||
const aTo = a.dmax != null ? a.dmax : a.ed | ||
const bTo = b.dmax != null ? b.dmax : b.ed | ||
if (aTo < bTo) return -1 | ||
@@ -207,0 +207,0 @@ if (aTo > bTo) return 1 |
@@ -1,90 +0,123 @@ | ||
import { Milliseconds, Grid, EVENT_HEIGHT } from "../constants" | ||
import { RawEv3nt } from "../models/event"; | ||
import { Milliseconds, EVENT_ROW_HEIGHT, Pixels } from "../constants" | ||
import { Ev3nt, RawEv3nt } from "../models/event" | ||
import { calcPixelsPerMillisecond } from './index' | ||
export class OrderedEvents { | ||
events: RawEv3nt[] = [] | ||
// grid: Grid = [] | ||
row_count: number = 0 | ||
interface InputBand { | ||
events: RawEv3nt[] | ||
zoomLevel: number | ||
} | ||
export interface OrderedBand { | ||
events: Ev3nt[] | ||
pixelsPerMillisecond?: Pixels | ||
rowCount: number | ||
zoomLevel: number | ||
} | ||
interface Options { | ||
parent?: RawEv3nt, | ||
bands: InputBand[] | ||
viewportWidth: Pixels, | ||
} | ||
const pixelsPerLetter = 8 | ||
export class OrderedTimeline { | ||
bands: OrderedBand[] | ||
from: Milliseconds | ||
parent: Ev3nt | ||
time: Milliseconds | ||
to: Milliseconds | ||
} | ||
export function orderEvents(events: RawEv3nt[], pixelsPerMillisecond: Milliseconds): OrderedEvents { | ||
if (!events.length) return new OrderedEvents() | ||
export function orderEvents(options: Options): OrderedTimeline { | ||
if (options.bands == null || !options.bands.length) return new OrderedTimeline() | ||
/** Keep a count the number of rows. It's returned to the main thread to construct the events bar and indicators */ | ||
let rowCount: number = 0 | ||
let from = options.bands.reduce((prev, curr) => { | ||
const firstEvent = curr.events[0] | ||
return Math.min(prev, firstEvent.dmin || Infinity, firstEvent.d || Infinity) | ||
}, Infinity) | ||
/** | ||
* The grid exists of rows of cells. A cell is an event defined by it's left position and width: | ||
* cell = [left, width], row = [cell, cell, etc], grid = [row, row, etc] | ||
*/ | ||
const grid: Grid = [] | ||
let to = options.bands.reduce((prev, curr) => { | ||
const highest = curr.events.reduce((prev2, curr2) => { | ||
return Math.max(prev2, curr2.d || - Infinity, curr2.ed || -Infinity, curr2.dmax || -Infinity) | ||
}, -Infinity) | ||
return Math.max(highest, prev) | ||
}, -Infinity) | ||
const paddingRight = EVENT_HEIGHT * 2 / pixelsPerMillisecond | ||
let parent | ||
if (options.parent != null) { | ||
parent = new Ev3nt(options.parent) as Ev3nt | ||
from = Math.min(from, parent.dmin || Infinity, parent.d || Infinity) | ||
to = Math.max(to, parent.ed || -Infinity, parent.dmax || -Infinity) | ||
} | ||
const addRow = (event: RawEv3nt): RawEv3nt => { | ||
// Create a variable to hold the row to find | ||
let row: number | ||
const time = to - from | ||
function processBand(band: InputBand) { | ||
const pixelsPerMillisecond = calcPixelsPerMillisecond(options.viewportWidth, band.zoomLevel, time) | ||
if (event.label == null) event.label = 'NO LABEL' | ||
event.from = event.date_min || event.date | ||
event.to = event.end_date_max || event.end_date | ||
if (event.to == null) event.to = event.from | ||
event.time = event.to == null ? 0 : event.to - event.from | ||
// If the event is a Point in Time, we use the label width to determine the width | ||
event.space = 0 | ||
if (!event.time) { | ||
if (event.label == null) event.label = 'NO LABEL' | ||
event.space = ((event.label.length * pixelsPerLetter) / pixelsPerMillisecond) + paddingRight | ||
const rows: number[] = [-Infinity] | ||
const imageSize: Milliseconds = Math.round(EVENT_ROW_HEIGHT * 2 / pixelsPerMillisecond) | ||
function rowHasSpace(row: number, imageFrom: Milliseconds) { | ||
return (rows[row + 1] == null || rows[row + 1] < imageFrom) && (rows[row + 2] == null || rows[row + 2] < imageFrom) | ||
} | ||
// Search the grid for a row which has space for the current event | ||
let rowIterator = 0 | ||
while (row == null && rowIterator < grid.length) { | ||
let cellIterator = 0 | ||
let hasSpace = true | ||
function addRow(rawEvent: RawEv3nt): Ev3nt { | ||
const event = new Ev3nt(rawEvent, pixelsPerMillisecond) | ||
while (hasSpace && cellIterator < grid[rowIterator].length) { | ||
// If event.to is smaller than cell.from, the rest of the cells | ||
// will also be "after" `event` and we don't have to check the rest, | ||
// so break | ||
if (event.to < grid[rowIterator][cellIterator][0]) break; | ||
let row: number | ||
if (event.img) { | ||
// A point in time with an image starts half an image earlier than the point (in time) | ||
const imageFrom = event.time ? event.from : event.from - imageSize / 2 | ||
const imageTo = event.time ? event.from + imageSize : event.from + imageSize / 2 | ||
// Check if event.from is greater than cell.to, otherwise | ||
// there is overlap and hence no space | ||
hasSpace = event.from > grid[rowIterator][cellIterator][1] | ||
cellIterator++ | ||
} | ||
row = rows.findIndex(r => imageFrom > r) | ||
if (hasSpace) { | ||
grid[rowIterator].push([event.from, event.from + event.time + event.space]) | ||
row = rowIterator | ||
} | ||
if (row > -1) { | ||
let hasSpace = false | ||
while (!hasSpace) { | ||
hasSpace = rowHasSpace(row, imageFrom) | ||
if (hasSpace) break | ||
row = rows.findIndex((r, i) => i > row && imageFrom > r) | ||
if (row === -1) hasSpace = true | ||
} | ||
} | ||
rowIterator++ | ||
} | ||
if (row === -1) { | ||
row = rows.push(event.screenTo) - 1 | ||
rows.push(imageTo) | ||
rows.push(imageTo) | ||
} else { | ||
rows[row] = event.screenTo | ||
rows[row + 1] = imageTo | ||
rows[row + 2] = imageTo | ||
} | ||
} else { | ||
row = rows.findIndex(r => event.from > r) | ||
// If row is undefined, it means there is no space in the current grid and | ||
// we need to add an extra row to the grid | ||
if (row == null) row = grid.push([[event.from, event.from + event.time + event.space]]) - 1 | ||
if (row === -1) { | ||
row = rows.push(event.screenTo) - 1 | ||
} else { | ||
rows[row] = event.screenTo | ||
} | ||
} | ||
// Increment the row count if necessary | ||
if (row > rowCount) rowCount = row | ||
event.row = row | ||
// Add the found row to the event | ||
event.row = row | ||
return event | ||
} | ||
return event | ||
return { | ||
events: band.events.map(addRow), | ||
zoomLevel: band.zoomLevel, | ||
pixelsPerMillisecond, | ||
rowCount: rows.length, | ||
} | ||
} | ||
events = events.map(addRow) | ||
return { | ||
events, | ||
// from, | ||
// to, | ||
// grid, | ||
row_count: grid.length | ||
bands: options.bands.map(processBand), | ||
from, | ||
parent, | ||
time, | ||
to, | ||
} | ||
@@ -91,0 +124,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { RawEv3nt } from "../models/event"; | ||
import { Ev3nt } from "../models/event"; | ||
import { Milliseconds, Ratio, Pixels } from "../constants"; | ||
@@ -12,10 +12,2 @@ | ||
// export const onVisible = (from, to) => (e: RawEv3nt) => { | ||
// const eventFrom = e.date_min || e.date | ||
// let eventTo = e.end_date_max || e.end_date | ||
// if (eventTo == null) eventTo = eventFrom | ||
// if (eventFrom == null && eventTo == null) return false | ||
// return !(eventTo < from || eventFrom > to) | ||
// } | ||
/** | ||
@@ -67,6 +59,7 @@ * Convert a zoom level to a visible ratio | ||
const d = new Date(ts) | ||
return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}` | ||
return d.toUTCString() | ||
// return `${d.getUTCFullYear()}-${d.getUTClMonth() + 1}-${d.getDate()}` | ||
} | ||
export function logEvent(event: RawEv3nt, ...rest: string[]) { | ||
console.log(event.label, event, event.left, formatDate(event.from), formatDate(event.to), rest) | ||
export function logEvent(event: Ev3nt, ...rest: string[]) { | ||
console.log(event.lbl, event, formatDate(event.from), formatDate(event.to), rest) | ||
} |
import BandView from './index' | ||
import eventBus from '../../event-bus' | ||
import EventsBand from '../../models/band/events' | ||
import { logEvent } from '../../utils' | ||
import { OnSelectFunction } from '../../index' | ||
import { EventType } from '../../constants'; | ||
// import { logEvent } from '../../utils' | ||
// import { OnSelectFunction } from '../../index' | ||
// import props from '../../models/props'; | ||
export default class EventsBandView extends BandView { | ||
constructor(public band: EventsBand, private select: OnSelectFunction) { | ||
constructor(public band: EventsBand) { | ||
super(band) | ||
@@ -30,6 +32,4 @@ } | ||
const event = this.band.getEventByCoordinates(ev.clientX, ev.clientY) | ||
if (event && this.select) { | ||
this.select(event) | ||
logEvent(event) | ||
} | ||
eventBus.dispatch(EventType.Select, event) | ||
} | ||
@@ -36,0 +36,0 @@ |
@@ -7,3 +7,3 @@ import Band, { BandType } from '../../models/band' | ||
import View from '../index' | ||
import { Milliseconds, Pixels, SCROLL_DONE } from '../../constants' | ||
import { Milliseconds, Pixels, EventType } from '../../constants' | ||
import { MinimapBandConfig, EventsBandConfig } from '../../models/config' | ||
@@ -114,3 +114,3 @@ import EventsBand from '../../models/band/events' | ||
if (this.lastDragInterval > 200 || significantDrag) { | ||
document.dispatchEvent(new CustomEvent(SCROLL_DONE)) | ||
eventBus.dispatch(EventType.ScrollDone) | ||
} | ||
@@ -117,0 +117,0 @@ } |
import createElement from '../../utils/create-element' | ||
import props from '../../models/props' | ||
import { EVENT_HEIGHT, PIXELS_PER_LETTER, DATE_BAR_HEIGHT } from '../../constants' | ||
import { EVENT_HEIGHT, FONT_SIZE, IMAGE_BOUNDING_BOX, IMAGE_SIZE, IMAGE_BORDER_SIZE, EventType } from '../../constants' | ||
import MinimapBand from '../../models/band/minimap' | ||
@@ -9,3 +9,4 @@ import animator from '../../animator' | ||
import drawRulers from './rulers' | ||
import { BandType } from '../../models/band'; | ||
import eventBus from '../../event-bus' | ||
import { Ev3nt } from '../../models/event' | ||
@@ -26,4 +27,67 @@ /** | ||
animator.registerView(this) | ||
eventBus.register(EventType.ZoomDone, this.onAnimationDone) | ||
eventBus.register(EventType.ScrollDone, this.onAnimationDone) | ||
} | ||
private async updateImages() { | ||
for (const band of props.eventsBands) { | ||
for (const event of band.visibleEvents) { | ||
if (event.img == null) continue | ||
if (event.image == null) { | ||
const path = `${props.imagePath}/${event.wid}__${IMAGE_SIZE}.${event.img}` | ||
event.image = new Image() | ||
const onImgLoad = this.onImgLoad(event) | ||
event.image.addEventListener('load', onImgLoad) | ||
event.image.addEventListener('error', onImgLoad) | ||
event.image.src = path | ||
} else { | ||
this.drawImage(event) | ||
} | ||
} | ||
} | ||
} | ||
private onImgLoad = (event: Ev3nt) => { | ||
const callback = (ev: Event) => { | ||
event.image.removeEventListener('load', callback) | ||
event.image.removeEventListener('error', callback) | ||
if (ev.type === 'error') { | ||
event.image = null | ||
return | ||
} | ||
if (event.image.width > event.image.height) { | ||
// First set the height, so we can use the old width | ||
event.image.height = Math.round(event.image.height * (IMAGE_BOUNDING_BOX / event.image.width)) | ||
event.image.width = IMAGE_BOUNDING_BOX | ||
} else { | ||
// First set the width, so we can use the old height | ||
event.image.width = Math.round(event.image.width * (IMAGE_BOUNDING_BOX / event.image.height)) | ||
event.image.height = IMAGE_BOUNDING_BOX | ||
} | ||
this.drawImage(event) | ||
} | ||
return callback | ||
} | ||
// Border uses fillRect instead of strokeRect, because strokeRect gives a different color. Don't ask me why. | ||
private drawImage(event: Ev3nt) { | ||
if (event.image == null || !event.image.complete || !event.image.naturalWidth) return | ||
const x = event.time ? event.left : event.left - (event.image.width / 2) - IMAGE_BORDER_SIZE | ||
const y = event.top - event.image.height | ||
this.ctx.fillStyle = event.color | ||
this.ctx.fillRect(x, y - IMAGE_BORDER_SIZE * 2, event.image.width + IMAGE_BORDER_SIZE * 2, event.image.height + IMAGE_BORDER_SIZE * 2) | ||
this.ctx.drawImage(event.image, x + IMAGE_BORDER_SIZE, y - IMAGE_BORDER_SIZE, event.image.width, event.image.height) | ||
} | ||
private onAnimationDone = () => { | ||
// this.updateImages() | ||
} | ||
render() { | ||
@@ -66,11 +130,12 @@ this.canvas = createElement('canvas', 'main', [ | ||
update = () => { | ||
props.bands | ||
.forEach(band => { | ||
if (band.type === BandType.EventsBand) | ||
this.drawEventsBand(band as EventsBand) | ||
else | ||
this.drawMinimapBand(band as MinimapBand) | ||
}) | ||
for (const band of props.eventsBands) { | ||
this.drawEventsBand(band) | ||
} | ||
for (const band of props.minimapBands) { | ||
this.drawMinimapBand(band) | ||
} | ||
this.drawIndicators() | ||
this.updateImages() | ||
} | ||
@@ -93,4 +158,30 @@ | ||
} else { | ||
let left = event.left | ||
let width = event.width | ||
if (event.uncertain_from_width > 1) { | ||
const gradient = this.ctx.createLinearGradient(event.left, 0, event.left + event.uncertain_from_width, 0) | ||
gradient.addColorStop(0, 'white') | ||
gradient.addColorStop(1, event.color) | ||
this.ctx.fillStyle = gradient | ||
this.ctx.fillRect(event.left, event.top, event.uncertain_from_width, EVENT_HEIGHT) | ||
left = event.left + event.uncertain_from_width | ||
width -= event.uncertain_from_width | ||
} | ||
if (event.uncertain_to_width > 1) { | ||
width -= event.uncertain_to_width | ||
const gradientLeft = left + width | ||
const gradientWidth = gradientLeft + event.uncertain_to_width | ||
const gradient = this.ctx.createLinearGradient(gradientLeft, 0, gradientWidth, 0) | ||
gradient.addColorStop(0, event.color) | ||
gradient.addColorStop(1, 'white') | ||
this.ctx.fillStyle = gradient | ||
this.ctx.fillRect(gradientLeft, event.top, event.uncertain_to_width, EVENT_HEIGHT) | ||
} | ||
this.ctx.fillStyle = event.color | ||
this.ctx.fillRect(event.left, event.top, event.width, EVENT_HEIGHT) | ||
this.ctx.fillRect(left, event.top, width, EVENT_HEIGHT) | ||
} | ||
@@ -103,19 +194,16 @@ } | ||
private drawEventsText(band: EventsBand) { | ||
this.ctx.font = '11px sans-serif' | ||
this.ctx.font = `${FONT_SIZE}px sans-serif` | ||
this.ctx.fillStyle = `rgb(40, 40, 40)` | ||
for (const event of band.visibleEvents) { | ||
let eventWidth = event.time === 0 ? event.padding : event.width | ||
let eventLeft = event.left | ||
if (event.left < 0 && event.time !== 0) { | ||
eventWidth = event.width + event.left | ||
eventLeft = 0 | ||
eventLeft = -event.uncertain_from_width | ||
} | ||
let eventLabelLength = event.label.length * PIXELS_PER_LETTER | ||
if (eventLabelLength <= eventWidth) { | ||
const paddingLeft = event.time ? 3 : 8 | ||
this.ctx.fillText(event.label, eventLeft + paddingLeft, event.top + EVENT_HEIGHT - 3) | ||
} | ||
const paddingLeft = event.time ? FONT_SIZE / 3 : FONT_SIZE / 1.2 | ||
const x = eventLeft + paddingLeft + event.uncertain_from_width | ||
const y = event.top + FONT_SIZE + ((EVENT_HEIGHT - FONT_SIZE) / 2) - 2 | ||
this.ctx.fillText(event.lbl, Math.round(x), Math.round(y)) | ||
} | ||
@@ -159,3 +247,3 @@ } | ||
// Cover the DATE_BAR | ||
this.indicatorsCtx.rect(leftIndicatorRightX, indicatorTOP + band.visibleHeight - DATE_BAR_HEIGHT, rightIndicatorLeftX - leftIndicatorRightX, DATE_BAR_HEIGHT) | ||
this.indicatorsCtx.rect(leftIndicatorRightX, indicatorTOP + band.availableHeight, rightIndicatorLeftX - leftIndicatorRightX, band.visibleHeight - band.availableHeight) | ||
} | ||
@@ -162,0 +250,0 @@ |
import MinimapBand from "../../models/band/minimap" | ||
import EventsBand from "../../models/band/events" | ||
import props from "../../models/props" | ||
import { Milliseconds } from "../../constants" | ||
import { Milliseconds, FONT_SIZE } from "../../constants" | ||
import { labelBody, Granularity } from "../../utils/dates" | ||
const smallFont: string = "11px sans-serif" | ||
const bigFont: string = "13px sans-serif" | ||
function isSpecialRuler(date: Milliseconds, band: MinimapBand | EventsBand) { | ||
@@ -28,3 +25,2 @@ if (band.granularity === Granularity.CENTURY && new Date(date).getUTCFullYear() % 1000 === 0) return true | ||
// let date = findClosestRulerDate(band.from, band.granularity) | ||
let date = band.nextDate(band.from) | ||
@@ -47,3 +43,3 @@ const y = band.config.topOffsetRatio * props.viewportHeight | ||
ctx.beginPath() | ||
ctx.font = smallFont | ||
ctx.font = `${FONT_SIZE}px sans-serif` | ||
// Normal ruler font fill | ||
@@ -61,3 +57,3 @@ ctx.fillStyle = `rgb(205, 205, 205)` | ||
ctx.beginPath() | ||
ctx.font = bigFont | ||
ctx.font = `${FONT_SIZE * 1.2}px sans-serif` | ||
// Special ruler font fill | ||
@@ -64,0 +60,0 @@ ctx.fillStyle = `rgb(120, 120, 120)` |
@@ -8,2 +8,3 @@ # Z-index | ||
4 red line | ||
10 popup | ||
10 debug |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
1404924
121
53804