diff --git a/example/index.html b/example/index.html index 8e238f7..b3eeab9 100644 --- a/example/index.html +++ b/example/index.html @@ -4,12 +4,18 @@ diff --git a/src/index.ts b/src/index.ts index 57a3ec3..3e1c6e5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,7 @@ -import { TimeGraph, TimeGraphModel } from "./time-graph"; -// import { TimeAxis } from "./time-axis"; +import { TimeGraph } from "./time-graph"; +import { TimeGraphModel } from "./time-graph-model"; +import { TimeGraphAxis } from "./time-graph-axis"; +import { TimeGraphChart } from "./time-graph-chart"; // const timeGraphSimple: TimeGraphModel = { // id: 'test1', @@ -112,26 +114,30 @@ const timeGraph: TimeGraphModel = { ] }, { + range: { + start: 1000, + end: 2000 + }, states: [ { label: 'state2.1', range: { - start: 145, - end: 255 + start: 1145, + end: 1255 } }, { label: 'state2.2', range: { - start: 265, - end: 275 + start: 1265, + end: 1275 } }, { label: 'state2.3', range: { - start: 365, - end: 555 + start: 1365, + end: 1555 } } ] @@ -139,38 +145,28 @@ const timeGraph: TimeGraphModel = { ] } +const tg = new TimeGraph('main', timeGraph); +const timeAxis = new TimeGraphAxis({ + id: 'timeGraphAxis', + height: 30, + width: 500 +}, timeGraph.range, tg.controller); -// const tg = new TimeGraph('main'); - -// const timeAxis = new TimeAxis({ -// id: 'timeAxis', -// height: 30, -// width: 6000 -// }); -// tg.setTimeAxis(timeAxis) - -// r1 = new TimeGraphRow(row-config) -// r2 = new TimeGraphRow(row-config) - -// tg.addRows([r1, r2]) -// tg.removeRows([r2]) - -// s1 = new TimeGraphState(state-config) -// s2 = new TimeGraphState(state-config) - -// r = tg.findRow(row-id) -// r.addStates([s1]) -// r1.addStates([s2]) - -const chart = new TimeGraph('main', timeGraph); -chart.render(); +const timeGraphChart = new TimeGraphChart({ + id: timeGraph.id + '_chart', + height: 300, + width: 500 +}, timeGraph.range, tg.controller); +timeGraphChart.addRows(timeGraph.rows); +tg.timeGraphAxis = timeAxis; +tg.timeGraphChart = timeGraphChart; export type TestFieldId = 'test0' | 'test1' | 'test2' | 'test3' | 'test4' | 'test5' | 'test6' | 'test7' | 'test8' | 'test9'; -export function tgTest(id: TestFieldId, val:string){ +export function tgTest(id: TestFieldId, val: string) { const f = document.getElementById(id); - if(f){ + if (f) { f.innerHTML = val; } } \ No newline at end of file diff --git a/src/time-axis-controller.ts b/src/time-axis-controller.ts deleted file mode 100644 index 5e66a18..0000000 --- a/src/time-axis-controller.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { TimeAxisScale } from "./time-axis-scale"; -import { TimeGraphRange } from "./time-graph"; - -export class TimeAxisController { - - protected totalRange: TimeGraphRange; - protected visibleRange: TimeGraphRange; - - constructor(protected timeAxis: TimeAxisScale) { - - } -} \ No newline at end of file diff --git a/src/time-axis.ts b/src/time-axis.ts deleted file mode 100644 index afed534..0000000 --- a/src/time-axis.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { TimeGraphContextOptions, TimeGraphContainer } from "./time-graph"; - -export class TimeAxis { - - protected application: PIXI.Application; - - constructor(config: TimeGraphContextOptions) { - const canvas: HTMLCanvasElement = document.createElement('canvas'); - canvas.width = config.width; - canvas.height = config.height; - canvas.id = config.id; - canvas.className = 'time-graph-canvas'; - this.application = new PIXI.Application({ - width: config.width, - height: config.height, - view: canvas, - backgroundColor: config.backgroundColor || 0x000000 - }); - - } - - getViewElement(): HTMLCanvasElement { - return this.application.view; - } - - getStage(): TimeGraphContainer { - return this.application.stage; - } - - -} \ No newline at end of file diff --git a/src/time-cursor.ts b/src/time-cursor.ts deleted file mode 100644 index b723814..0000000 --- a/src/time-cursor.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { TimeGraphComponent } from "./time-graph-component"; - -export class TimeCursor extends TimeGraphComponent { - - render(): void { - throw new Error("Method not implemented."); - } - -} \ No newline at end of file diff --git a/src/time-graph-axis-scale.ts b/src/time-graph-axis-scale.ts new file mode 100644 index 0000000..bd4bb19 --- /dev/null +++ b/src/time-graph-axis-scale.ts @@ -0,0 +1,19 @@ +import { TimeGraphComponent, TimeGraphRect } from "./time-graph-component"; + +export class TimeGraphAxisScale extends TimeGraphComponent { + + constructor(id: string, protected options: TimeGraphRect) { + super(id); + } + + render() { + this.rect({ + color: 0xFF0000, + height: this.options.height, + width: this.options.width, + position: this.options.position + }); + console.log("render axis", this.options.width); + } + +} \ No newline at end of file diff --git a/src/time-graph-axis.ts b/src/time-graph-axis.ts new file mode 100644 index 0000000..a35a48e --- /dev/null +++ b/src/time-graph-axis.ts @@ -0,0 +1,34 @@ +import { TimeGraphAxisScale } from "./time-graph-axis-scale"; +import { TimeGraphContainer, TimeGraphContainerOptions } from "./time-graph-container"; +import { TimeGraphRange } from "./time-graph-model"; +import { TimeGraphStateController } from "./time-graph-state-controller"; + +export class TimeGraphAxis extends TimeGraphContainer { + + constructor(protected canvasOpts: TimeGraphContainerOptions, protected range: TimeGraphRange, protected controller: TimeGraphStateController) { + super({ + id: canvasOpts.id, + height: canvasOpts.height, + width: canvasOpts.width, + backgroundColor: 0xAA30f0 + }, controller); + + this.update(); + this.controller.zoomAndPanController.addMousewheelZoomAndPan(this.canvas); + } + + update() { + this.stage.removeChildren(); + const scaleComponent = new TimeGraphAxisScale(this.canvasOpts.id + '_scale', { + height: 30, + width: (this.range.end - this.range.start) * this._controller.zoomFactor, + position: { + x: this._controller.positionOffset.x, + y: 0 + } + }); + + this.addChild(scaleComponent); + this.controller.zoomAndPanController.addDnDZoomAndPan(scaleComponent.displayObject); + } +} \ No newline at end of file diff --git a/src/time-graph-chart.ts b/src/time-graph-chart.ts new file mode 100644 index 0000000..98c4ac1 --- /dev/null +++ b/src/time-graph-chart.ts @@ -0,0 +1,59 @@ +import { TimeGraphContainer, TimeGraphContainerOptions } from "./time-graph-container"; +import { TimeGraphRowElement } from "./time-graph-row-element"; +import { TimeGraphRow } from "./time-graph-row"; +import { TimeGraphRowModel, TimeGraphRowElementModel, TimeGraphRange } from "./time-graph-model"; +import { TimeGraphStateController } from "./time-graph-state-controller"; + +export class TimeGraphChart extends TimeGraphContainer { + + protected rows: TimeGraphRowModel[]; + + constructor(canvasOpts: TimeGraphContainerOptions, protected range: TimeGraphRange, controller: TimeGraphStateController) { + super({ + id: canvasOpts.id, + height: canvasOpts.height, + width: canvasOpts.width, + backgroundColor: 0xFFFFFF + }, controller); + this.rows = []; + } + + addRow(row: TimeGraphRowModel) { + const height = 20; + const rowId = 'row_' + this._stage.children.length; + const rowComponent = new TimeGraphRow(rowId, { + position: { + x: 0, // TODO must be calculated by zoom and pan + y: (height * this.rows.length) + height / 2 + }, + width: this.range.end + }); + this.addChild(rowComponent); + this.rows.push(row); + + row.states.forEach((rowElement: TimeGraphRowElementModel, idx: number) => { + const newRowElement: TimeGraphRowElementModel = { + label: rowElement.label, + range: { + start: (rowElement.range.start * this._controller.zoomFactor) + this._controller.positionOffset.x, + end: (rowElement.range.end * this._controller.zoomFactor) + this._controller.positionOffset.x + } + } + const el = new TimeGraphRowElement(rowId + '_el_' + idx, newRowElement, rowComponent); + this.addChild(el); + }); + } + + addRows(rows: TimeGraphRowModel[]) { + this.rows = []; + rows.forEach(row => { + this.addRow(row); + }) + } + + update() { + this.stage.removeChildren(); + this.addRows(this.rows); + } + +} \ No newline at end of file diff --git a/src/time-graph-component.ts b/src/time-graph-component.ts index 166e070..5c9a4f6 100644 --- a/src/time-graph-component.ts +++ b/src/time-graph-component.ts @@ -1,91 +1,69 @@ -import { TimeGraphContainer, TimeGraphApplication } from "./time-graph"; -import { TimeGraphController } from "./time-graph-controller"; - export type TimeGraphInteractionType = 'mouseover' | 'mouseout' | 'mousemove' | 'mousedown' | 'mouseup' | 'mouseupoutside' | 'click'; export type TimeGraphInteractionHandler = (event: PIXI.interaction.InteractionEvent) => void; -export type TimeGraphInteractionHandlerMap = Map -export interface TimeGraphDisplayObject { +export interface TimeGraphElementStyle { color?: number opacity?: number } - -export interface TimeGraphRect extends TimeGraphDisplayObject { +export interface TimeGraphElementPosition { x: number y: number - w: number - h: number } - -export interface TimeGraphLine extends TimeGraphDisplayObject { - start: { - x: number - y: number - } - end: { - x: number - y: number - } - width?: number +export interface TimeGraphHorizontalElement { + position: TimeGraphElementPosition + width: number } +export interface TimeGraphVerticalElement { + position: TimeGraphElementPosition + height: number +} +export interface TimeGraphLineStyle extends TimeGraphElementStyle { + thickness?: number +} +export type TimeGraphRect = TimeGraphHorizontalElement & TimeGraphVerticalElement; +export type TimeGraphStyledRect = TimeGraphRect & TimeGraphElementStyle; +export type TimeGraphHorizontalLine = TimeGraphHorizontalElement & TimeGraphLineStyle; +export type TimeGraphVerticalLine = TimeGraphVerticalElement & TimeGraphLineStyle; export abstract class TimeGraphComponent { + protected _displayObject: PIXI.Graphics; - protected _ctx: TimeGraphContainer; - protected _id: string; - protected _controller: TimeGraphController; - protected displayObject: PIXI.Graphics; - protected options: TimeGraphDisplayObject; - - constructor(id: string, protected app: TimeGraphApplication, timeGraphController: TimeGraphController) { - this._id = id; - this._ctx = app.stage; - this._controller = timeGraphController; - this.displayObject = new PIXI.Graphics(); - this._ctx.addChild(this.displayObject); + constructor(protected _id: string) { + this._displayObject = new PIXI.Graphics(); } get id(): string { return this._id; } - get context(): TimeGraphContainer { - return this._ctx; + get displayObject(): PIXI.Graphics { + return this._displayObject; } - get controller(): TimeGraphController { - return this._controller; + clear() { + this._displayObject.clear(); } abstract render(): void; - clear(){ - this.displayObject.clear(); - } - - rect(opts: TimeGraphRect) { - const { x, y, w, h, color } = opts; - const c = this.controller; - const calcX = (x * c.zoomFactor) + c.positionOffset.x ; - const calcW = w * c.zoomFactor; + protected rect(opts: TimeGraphStyledRect) { + const { position, width, height, color } = opts; this.displayObject.beginFill((color || 0x000000)); - this.displayObject.drawRect(calcX, y, calcW, h); + this.displayObject.drawRect(position.x, position.y, width, height); this.displayObject.endFill(); } - line(opts: TimeGraphLine) { - const { width, color } = opts; - this.displayObject.lineStyle(width || 1, color || 0x000000); - this.displayObject.moveTo(opts.start.x, opts.start.y); - this.displayObject.lineTo((opts.end.x * this.controller.zoomFactor), opts.end.y); + protected hline(opts: TimeGraphHorizontalLine) { + const { position, width, thickness, color } = opts; + this.displayObject.lineStyle(thickness || 1, color || 0x000000); + this.displayObject.moveTo(position.x, position.y); + this.displayObject.lineTo(position.x + width, position.y); } - protected addEvent(event: TimeGraphInteractionType, handler: TimeGraphInteractionHandler) { - this.displayObject.interactive = true; - this.displayObject.on(event, (e: PIXI.interaction.InteractionEvent) => { - if (handler) { - handler(e); - } - }); + protected vline(opts: TimeGraphVerticalLine) { + const { position, height, thickness, color } = opts; + this.displayObject.lineStyle(thickness || 1, color || 0x000000); + this.displayObject.moveTo(position.x, position.y); + this.displayObject.lineTo(position.x, position.y + height); } } \ No newline at end of file diff --git a/src/time-graph-container.ts b/src/time-graph-container.ts new file mode 100644 index 0000000..e2f4021 --- /dev/null +++ b/src/time-graph-container.ts @@ -0,0 +1,53 @@ +import { TimeGraphComponent } from "./time-graph-component"; +import * as PIXI from "pixi.js"; +import { TimeGraphStateController } from "./time-graph-state-controller"; + +export interface TimeGraphContainerOptions { + id: string + width: number + height: number + backgroundColor?: number +} + +export abstract class TimeGraphContainer { + + protected _stage: PIXI.Container; + protected _canvas: HTMLCanvasElement; + + protected _controller: TimeGraphStateController; + + constructor(config: TimeGraphContainerOptions, controller: TimeGraphStateController) { + const canvas: HTMLCanvasElement = document.createElement('canvas'); + canvas.width = config.width; + canvas.height = config.height; + canvas.id = config.id; + canvas.className = 'time-graph-canvas'; + const application = new PIXI.Application({ + width: config.width, + height: config.height, + view: canvas, + backgroundColor: config.backgroundColor || 0x000000 + }); + application.stage.height = config.height; + + this._stage = application.stage; + this._canvas = application.view; + + this._controller = controller; + } + + get canvas(): HTMLCanvasElement { + return this._canvas; + } + + get stage(): PIXI.Container { + return this._stage; + } + + protected addChild(child: TimeGraphComponent) { + child.render(); + this._stage.addChild(child.displayObject); + } + + abstract update(): void; +} \ No newline at end of file diff --git a/src/time-axis-scale.ts b/src/time-graph-interaction.ts similarity index 66% rename from src/time-axis-scale.ts rename to src/time-graph-interaction.ts index 11652e5..71a5d08 100644 --- a/src/time-axis-scale.ts +++ b/src/time-graph-interaction.ts @@ -1,23 +1,35 @@ -import { TimeGraphComponent, TimeGraphRect } from "./time-graph-component"; -import { TimeGraphApplication } from "./time-graph"; -import { TimeGraphController } from "./time-graph-controller"; +import { TimeGraphStateController } from "./time-graph-state-controller"; -export class TimeAxisScale extends TimeGraphComponent { +export type TimeGraphInteractionType = 'mouseover' | 'mouseout' | 'mousemove' | 'mousedown' | 'mouseup' | 'mouseupoutside' | 'click'; +export type TimeGraphInteractionHandler = (event: PIXI.interaction.InteractionEvent) => void; +export class TimeGraphInteraction { protected mouseStartY: number; protected mouseStartX: number; protected graphWidthStart: number; protected mouseIsDown: boolean = false; - constructor(id: string, ctx: TimeGraphApplication, timeGraphController: TimeGraphController) { - super(id, ctx, timeGraphController); + constructor(protected controller: TimeGraphStateController) {} + + addMousewheelZoomAndPan(canvas: HTMLCanvasElement) { + canvas.addEventListener('mousewheel', (ev: WheelEvent) => { + this.mouseStartX = ev.x; + this.graphWidthStart = this.controller.graphWidth; + this.zoom((ev.deltaY / 100) * (-1)); + this.setXOffset(ev.deltaX * (-1)); + this.setZoomAndPosition(); + return false; + }); + } + + addDnDZoomAndPan(displayObject: PIXI.DisplayObject) { this.addEvent('mousedown', event => { this.mouseStartY = event.data.global.y; this.mouseStartX = event.data.global.x; this.graphWidthStart = this.controller.graphWidth; this.mouseIsDown = true; - }); + }, displayObject); this.addEvent('mousemove', event => { if (this.mouseIsDown) { @@ -29,29 +41,21 @@ export class TimeAxisScale extends TimeGraphComponent { const deltaMouseX = event.data.global.x - this.mouseStartX; this.setXOffset(deltaMouseX); } - }); + }, displayObject); const mouseUp = (event: PIXI.interaction.InteractionEvent) => { this.mouseIsDown = false; this.setZoomAndPosition(); } - this.addEvent('mouseup', mouseUp); - this.addEvent('mouseupoutside', mouseUp); - this.app.view.addEventListener('mousewheel', (ev: WheelEvent) => { - this.mouseStartX = ev.x; - this.graphWidthStart = this.controller.graphWidth; - this.zoom((ev.deltaY / 100) * (-1)); - this.setXOffset(ev.deltaX * (-1)); - this.setZoomAndPosition(); - return false; - }); + this.addEvent('mouseup', mouseUp, displayObject); + this.addEvent('mouseupoutside', mouseUp, displayObject); } - setZoomAndPosition() { + protected setZoomAndPosition() { this.controller.oldZoomFactor = this.controller.zoomFactor; this.controller.oldPositionOffset = this.controller.positionOffset; } - setXOffset(deltaMouseX: number = 0) { + protected setXOffset(deltaMouseX: number = 0) { const c = this.controller; const normZoomFactor = c.graphWidth / this.graphWidthStart; const graphMouseStartX = (c.oldPositionOffset.x * (-1)) + this.mouseStartX; @@ -78,15 +82,12 @@ export class TimeAxisScale extends TimeGraphComponent { } } - render() { - this.options = { - color: 0xFF0000, - h: 30, - w: 6000, - x: 0, - y: 0 - }; - this.rect(this.options as TimeGraphRect); + protected addEvent(event: TimeGraphInteractionType, handler: TimeGraphInteractionHandler, displayObject: PIXI.DisplayObject) { + displayObject.interactive = true; + displayObject.on(event, (e: PIXI.interaction.InteractionEvent) => { + if (handler) { + handler(e); + } + }); } - } \ No newline at end of file diff --git a/src/time-graph-model.ts b/src/time-graph-model.ts new file mode 100644 index 0000000..affab9a --- /dev/null +++ b/src/time-graph-model.ts @@ -0,0 +1,21 @@ +export interface TimeGraphRange { + start: number + end: number +} + +export interface TimeGraphModel { + id: string + name: string + range: TimeGraphRange + rows: TimeGraphRowModel[] +} + +export interface TimeGraphRowModel { + range?: TimeGraphRange + states: TimeGraphRowElementModel[] +} + +export interface TimeGraphRowElementModel { + range: TimeGraphRange + label: string +} \ No newline at end of file diff --git a/src/time-graph-row-element.ts b/src/time-graph-row-element.ts new file mode 100644 index 0000000..5923fd0 --- /dev/null +++ b/src/time-graph-row-element.ts @@ -0,0 +1,26 @@ +import { TimeGraphComponent } from "./time-graph-component"; +import { TimeGraphRow } from "./time-graph-row"; +import { TimeGraphRowElementModel } from "./time-graph-model"; + +export class TimeGraphRowElement extends TimeGraphComponent { + + constructor(id: string, protected options: TimeGraphRowElementModel, protected row: TimeGraphRow) { + super(id); + } + + render() { + const height = 20; + const position = { + x: this.options.range.start, + y: this.row.position.y - (height / 2) + }; + const width = this.options.range.end - this.options.range.start; + + this.rect({ + color: 0xC80000, + height, + position, + width + }); + } +} \ No newline at end of file diff --git a/src/time-graph-row-view.ts b/src/time-graph-row-view.ts deleted file mode 100644 index 856b0b1..0000000 --- a/src/time-graph-row-view.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { TimeGraphState, TimeGraphStateView } from "./time-graph-state-view"; -import { TimeGraphComponent } from "./time-graph-component"; -import { TimeGraphRange, TimeGraphApplication } from "./time-graph"; -import { TimeGraphController } from "./time-graph-controller"; - -export interface TimeGraphRow { - start?: number - end?: number - states: TimeGraphState[] -} - -export class TimeGraphRowView extends TimeGraphComponent { - - protected height: number; - protected ypos: number; - protected width: number; - - constructor( - protected cid: string, - app: TimeGraphApplication, - protected rowIdx: number, - protected row: TimeGraphRow, - protected range: TimeGraphRange, - timeGraphController: TimeGraphController - ) { - super(cid, app, timeGraphController); - this.height = 20; - this.ypos = (this.height * this.rowIdx) + this.height / 2; - this.width = this.range.end - this.range.start; - } - - render() { - this.line({ - start: { x: 0, y: this.ypos }, - end: { x: this.width, y: this.ypos }, - color: 0x000000, - opacity: 0.2, - width: 1 - }); - - this.row.states.forEach(state => { - const timeGraphState = new TimeGraphStateView(this.id + state.label + state.range.start, this.app, state, this.ypos, this.range, this.controller); - timeGraphState.render(); - }); - } - -} \ No newline at end of file diff --git a/src/time-graph-row.ts b/src/time-graph-row.ts new file mode 100644 index 0000000..243c558 --- /dev/null +++ b/src/time-graph-row.ts @@ -0,0 +1,21 @@ +import { TimeGraphComponent, TimeGraphHorizontalElement, TimeGraphElementPosition } from "./time-graph-component"; + +export class TimeGraphRow extends TimeGraphComponent { + + constructor(id: string, protected options: TimeGraphHorizontalElement) { + super(id); + } + + render() { + this.hline({ + color: 0x000000, + opacity: 0.2, + width: this.options.width, + position: this.options.position + }); + } + + get position(): TimeGraphElementPosition { + return this.options.position; + } +} \ No newline at end of file diff --git a/src/time-graph-controller.ts b/src/time-graph-state-controller.ts similarity index 79% rename from src/time-graph-controller.ts rename to src/time-graph-state-controller.ts index ca610c4..9537321 100644 --- a/src/time-graph-controller.ts +++ b/src/time-graph-state-controller.ts @@ -1,7 +1,6 @@ -import { TimeGraphComponent } from "./time-graph-component"; -import { TimeGraphContainer } from "./time-graph"; +import { TimeGraphInteraction } from "./time-graph-interaction"; -export class TimeGraphController { +export class TimeGraphStateController { protected _originalGraphWidth: number; protected _zoomFactor: number; protected _initialZoomFactor: number; @@ -14,15 +13,13 @@ export class TimeGraphController { x: number; y: number; }; - protected _components: TimeGraphComponent[]; - protected _contexts: Map; protected zoomChangedHandler: (() => void)[]; protected positionChangedHandler: (() => void)[]; + protected _zoomAndPanController: TimeGraphInteraction; + constructor(protected _canvasWidth: number, protected _graphWidth: number) { - this._components = []; - this._contexts = new Map(); this._originalGraphWidth = _graphWidth; this._initialZoomFactor = _canvasWidth / _graphWidth; this._graphWidth = this._originalGraphWidth * this._initialZoomFactor; @@ -32,6 +29,11 @@ export class TimeGraphController { this._oldPositionOffset = { x: 0, y: 0 }; this.zoomChangedHandler = []; this.positionChangedHandler = []; + this._zoomAndPanController = new TimeGraphInteraction(this); + } + + get zoomAndPanController(): TimeGraphInteraction { + return this._zoomAndPanController; } protected handleZoomChange() { @@ -108,19 +110,4 @@ export class TimeGraphController { }) { this._oldPositionOffset = value; } - - get components(): TimeGraphComponent[] { - return this._components; - } - addComponent(component: TimeGraphComponent) { - this.addContext(component.id, component.context); - this._components.push(component); - } - - addContext(id: string, ctx: TimeGraphContainer) { - if (!this._contexts.get(id)) { - this._contexts.set(id, ctx); - - } - } } \ No newline at end of file diff --git a/src/time-graph-state-view.ts b/src/time-graph-state-view.ts deleted file mode 100644 index 6920aeb..0000000 --- a/src/time-graph-state-view.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { TimeGraphRange, TimeGraphApplication } from "./time-graph"; -import { TimeGraphComponent, TimeGraphRect } from "./time-graph-component"; -import { TimeGraphController } from "./time-graph-controller"; - -export interface TimeGraphState { - range: TimeGraphRange - label: string -} - -export class TimeGraphStateView extends TimeGraphComponent { - - protected start: number; - protected end: number; - protected y: number; - protected height: number; - - constructor(protected cid: string, app: TimeGraphApplication, protected state: TimeGraphState, yPosition: number, protected range: TimeGraphRange, controller: TimeGraphController) { - super(cid, app, controller); - - // TODO this calculation of the initial offset must be calculated differently later - this.start = state.range.start - range.start; - this.end = state.range.end - range.start; - - // TODO magic number 10 is the half of the row height...must come from a central style-config-provider later. - this.y = yPosition - 10; - // TODO magic number 20 must come from a central style-config-provider later. - this.height = 20; - } - - render() { - this.options = { - color: 0xC80000, - x: this.start, - y: this.y, - w: this.end - this.start, - h: this.height - }; - this.addEvent('mouseover', this.handleMouseOver); - this.addEvent('mouseout', this.handleMouseOut); - this.addEvent('mousedown', this.handleMouseDown); - this.addEvent('mouseup', this.handleMouseOut); - this.rect(this.options as TimeGraphRect); - } - - protected changeColor(color: number) { - this.displayObject.clear(); - this.options.color = color; - this.rect(this.options as TimeGraphRect); - } - - protected handleMouseOver = ((event: PIXI.interaction.InteractionEvent) => { - this.changeColor(0x00C800); - }).bind(this); - - protected handleMouseOut = ((event: PIXI.interaction.InteractionEvent) => { - this.changeColor(0xC80000); - }).bind(this); - - protected handleMouseDown = ((event: PIXI.interaction.InteractionEvent) => { - this.changeColor(0x0000C8); - }).bind(this); -} \ No newline at end of file diff --git a/src/time-graph.ts b/src/time-graph.ts index b20b12a..fc77ca3 100644 --- a/src/time-graph.ts +++ b/src/time-graph.ts @@ -1,123 +1,59 @@ -import { TimeGraphRow, TimeGraphRowView } from "./time-graph-row-view"; -import { TimeAxisScale } from "./time-axis-scale"; -import { TimeGraphController } from "./time-graph-controller"; -import * as PIXI from "pixi.js"; - -export interface TimeGraphRange { - start: number - end: number -} - -export interface TimeGraphModel { - id: string - name: string - range: TimeGraphRange - rows: TimeGraphRow[] -} - -export interface TimeGraphContextOptions { - id: string - width: number - height: number - backgroundColor?: number -} - -export type TimeGraphContainer = PIXI.Container -export type TimeGraphApplication = PIXI.Application; +import { TimeGraphAxis } from "./time-graph-axis"; +import { TimeGraphChart } from "./time-graph-chart"; +import { TimeGraphStateController } from "./time-graph-state-controller"; +import { TimeGraphModel } from "./time-graph-model"; +import { TimeGraphContainer } from "./time-graph-container"; export class TimeGraph { protected container?: HTMLElement; - protected timeGraphWidth: number; - protected containerWidth: number; - protected timeGraphController: TimeGraphController; - protected timeAxisApplication?: TimeGraphApplication; - protected timeGraphRowsApplication?: TimeGraphApplication; - protected timeAxis: TimeAxisScale; + protected axisContainer: HTMLElement; + protected chartContainer: HTMLElement; - constructor(id: string, protected model: TimeGraphModel) { - this.container = document.getElementById(id) || undefined; + protected tgContainers: TimeGraphContainer[]; + + protected _controller: TimeGraphStateController + + constructor(containerId: string, timeGraphModel: TimeGraphModel) { + this.container = document.getElementById(containerId) || undefined; if (!this.container) { - throw (`No container with id ${id} available.`); + throw (`No container with id ${containerId} available.`); } + this.container.innerHTML = ''; - this.timeGraphWidth = this.model.range.end; - this.containerWidth = this.container.clientWidth; - this.timeGraphController = new TimeGraphController(this.containerWidth, this.timeGraphWidth); + this.axisContainer = document.createElement('div'); + this.axisContainer.id = containerId + '_axis'; + this.container.appendChild(this.axisContainer); - this.timeAxisApplication = this.getNewApplication({ - id: 'timeAxis_' + this.model.id, - height: 30, - width: this.timeGraphWidth, - backgroundColor: 0xAA30f0 - }); - if (this.timeAxisApplication) { - this.timeAxis = new TimeAxisScale('timeAxis_' + this.model.id, this.timeAxisApplication, this.timeGraphController); - } + this.chartContainer = document.createElement('div'); + this.chartContainer.id = containerId + '_chart'; + this.container.appendChild(this.chartContainer); - this.timeGraphRowsApplication = this.getNewApplication({ - id: 'timeGraphRows_' + this.model.id, - width: this.timeGraphWidth, - height: 200, - backgroundColor: 0xFFFFFF - }); + this.tgContainers = []; - // let fw = true; - // setInterval(() => { - // if (this.timeGraphController.zoomFactor < 2 && fw) { - // this.timeGraphController.zoomFactor += 0.01; - // } else { - // fw = false; - // if (this.timeGraphController.zoomFactor > 0.02) { - // this.timeGraphController.zoomFactor -= 0.01; - // } else { - // fw = true; - // } - // } - // this.render(); - // }, 10); + this._controller = new TimeGraphStateController(this.container.clientWidth, timeGraphModel.range.end); - this.timeGraphController.onZoomChanged(() => { - this.render(); + this._controller.onZoomChanged(() => { + this.tgContainers.map(c => c.update()); }); - this.timeGraphController.onPositionChanged(() => { - this.render(); + this._controller.onPositionChanged(() => { + this.tgContainers.map(c => c.update()); }); } - protected getNewApplication(config: TimeGraphContextOptions): TimeGraphApplication | undefined { - if (this.container) { - const canvas: HTMLCanvasElement = document.createElement('canvas'); - canvas.width = config.width; - canvas.height = config.height; - canvas.id = config.id; - canvas.className = 'time-graph-canvas'; - const application = new PIXI.Application({ - width: config.width, - height: config.height, - view: canvas, - backgroundColor: config.backgroundColor || 0x000000 - }); - this.container.appendChild(canvas); - application.stage.height = config.height; - return application; - } + get controller(): TimeGraphStateController { + return this._controller; } - render() { - this.timeAxis.clear(); - this.timeGraphController.addComponent(this.timeAxis); - this.timeAxis.render(); + set timeGraphAxis(tga: TimeGraphAxis) { + this.axisContainer.innerHTML = ''; + this.tgContainers.push(tga); + this.axisContainer.appendChild(tga.canvas); + } - if(this.timeGraphRowsApplication){ - this.timeGraphRowsApplication.stage.removeChildren(); - } - this.model.rows.forEach((row: TimeGraphRow, idx: number) => { - if (this.timeGraphRowsApplication) { - const timeGraphRow = new TimeGraphRowView(this.model.id + 'row' + idx, this.timeGraphRowsApplication, idx, row, this.model.range, this.timeGraphController); - this.timeGraphController.addComponent(timeGraphRow); - timeGraphRow.render(); - } - }); + set timeGraphChart(tgc: TimeGraphChart) { + this.chartContainer.innerHTML = ''; + this.tgContainers.push(tgc); + this.chartContainer.appendChild(tgc.canvas); } } \ No newline at end of file