Skip to content

Commit

Permalink
Viewport Implementation
Browse files Browse the repository at this point in the history
Abstracts horizontal panning with the PIXI.js.  The beginning of timeline-chart performance optimization from POC.  See PR #213 for full change details.

Signed-off-by: Will Yang <william.yang@ericsson.com>
  • Loading branch information
williamsyang-work authored and bhufmann committed Nov 9, 2022
1 parent 1f50903 commit 16e8148
Show file tree
Hide file tree
Showing 16 changed files with 335 additions and 133 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ bundle.js
coverage
lib
node_modules
.vscode
15 changes: 6 additions & 9 deletions example/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { TimeGraphChart } from "timeline-chart/lib/layer/time-graph-chart";
import { TimeGraphUnitController } from "timeline-chart/lib/time-graph-unit-controller";
import { TimeGraphRowController } from "timeline-chart/lib/time-graph-row-controller";
import { TimeGraphNavigator } from "timeline-chart/lib/layer/time-graph-navigator";
import { TimeGraphContainer } from "timeline-chart/lib/time-graph-container";
import { TimeGraphChartCursors } from "timeline-chart/lib/layer/time-graph-chart-cursors";
import { TimeGraphChartSelectionRange } from "timeline-chart/lib/layer/time-graph-chart-selection-range";
import { TimeGraphAxisCursors } from "timeline-chart/lib/layer/time-graph-axis-cursors";
import { TimeGraphContainer } from "timeline-chart/lib/time-graph-container";
// import { timeGraph } from "timeline-chart/lib/test-data";
import { TimelineChart } from "timeline-chart/lib/time-graph-model";
import { TimeGraphStateStyle } from "timeline-chart/lib/components/time-graph-state";
Expand Down Expand Up @@ -36,6 +36,7 @@ container.style.width = styleConfig.mainWidth + "px";
const testDataProvider = new TestDataProvider(styleConfig.mainWidth);
let timeGraph = testDataProvider.getData({});
const unitController = new TimeGraphUnitController(timeGraph.totalLength);
unitController.worldRenderFactor = 3;
unitController.numberTranslator = (theNumber: bigint) => {
let num = theNumber.toString();
if (num.length > 6) {
Expand All @@ -54,11 +55,7 @@ const providers = {
};
},
dataProvider: (range: TimelineChart.TimeGraphRange, resolution: number) => {
const length = range.end - range.start;
const overlap = length * BigInt(10);
const start = range.start - overlap > BigInt(0) ? range.start - overlap : BigInt(0);
const end = range.end + overlap < unitController.absoluteRange ? range.end + overlap : unitController.absoluteRange;
const newRange: TimelineChart.TimeGraphRange = { start, end };
const newRange: TimelineChart.TimeGraphRange = range;
const newResolution: number = resolution * 0.1;
timeGraph = testDataProvider.getData({ range: newRange, resolution: newResolution });
return {
Expand Down Expand Up @@ -132,8 +129,9 @@ const timeGraphAxisContainer = new TimeGraphContainer({
}, unitController, axisCanvas);
axisHTMLContainer.appendChild(timeGraphAxisContainer.canvas);

const timeAxisCursors = new TimeGraphAxisCursors('timeGraphAxisCursors', { color: styleConfig.cursorColor });
const timeAxisLayer = new TimeGraphAxis('timeGraphAxis', { color: styleConfig.naviBackgroundColor, verticalAlign: 'bottom'});
timeGraphAxisContainer.addLayers([timeAxisLayer]);
timeGraphAxisContainer.addLayers([timeAxisLayer, timeAxisCursors]);

const chartHTMLContainer = document.createElement('div');
chartHTMLContainer.id = 'main_chart';
Expand All @@ -153,13 +151,12 @@ chartHTMLContainer.appendChild(timeGraphChartContainer.canvas);
const timeGraphChartGridLayer = new TimeGraphChartGrid('timeGraphGrid', rowHeight);
const timeGraphChart = new TimeGraphChart('timeGraphChart', providers, rowController);
const timeGraphChartArrows = new TimeGraphChartArrows('timeGraphChartArrows', rowController);
const timeAxisCursors = new TimeGraphAxisCursors('timeGraphAxisCursors', { color: styleConfig.cursorColor });
const timeGraphSelectionRange = new TimeGraphChartSelectionRange('chart-selection-range', { color: styleConfig.cursorColor });
const timeGraphChartCursors = new TimeGraphChartCursors('chart-cursors', timeGraphChart, rowController, { color: styleConfig.cursorColor });
const timeGraphChartRangeEvents = new TimeGraphRangeEventsLayer('timeGraphChartRangeEvents', providers);

timeGraphChartContainer.addLayers([timeGraphChartGridLayer, timeGraphChart,
timeGraphChartArrows, timeAxisCursors, timeGraphSelectionRange,
timeGraphChartArrows, timeGraphSelectionRange,
timeGraphChartCursors, timeGraphChartRangeEvents]);

timeGraphChart.registerMouseInteractions({
Expand Down
7 changes: 7 additions & 0 deletions timeline-chart/src/bigint-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,11 @@ export class BIMath {
val = BIMath.round(val);
return val >= 0 ? val : -val;
};

static readonly multiply = (a: bigint | number, b: bigint | number): bigint => {
a = Number(a);
b = Number(b);
let c = a * b;
return BIMath.round(c);
}
};
27 changes: 16 additions & 11 deletions timeline-chart/src/components/time-graph-axis-scale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class TimeGraphAxisScale extends TimeGraphComponent<null> {
return stepLength;
}

protected renderVerticalLines(drawLabels: boolean, lineColor: number, lineStyle: (label: string | undefined) => { lineHeight: number }) {
protected renderVerticalLines(drawLabels: boolean, lineColor: number, lineStyle: (label: string | undefined) => { lineHeight: number }, viewport?: boolean) {
if (this.unitController.viewRangeLength > 0 && this.stateController.canvasDisplayWidth > 0) {
let labelWidth = 0;
if (this.unitController.numberTranslator) {
Expand All @@ -79,12 +79,17 @@ export class TimeGraphAxisScale extends TimeGraphComponent<null> {
const stepLength = BigInt(this.getStepLength(labelWidth));
const canvasDisplayWidth = this.stateController.canvasDisplayWidth;
const zoomFactor = this.stateController.zoomFactor;
const viewRangeStart = this.unitController.viewRange.start + this.unitController.offset;
const viewRangeEnd = this.unitController.viewRange.end + this.unitController.offset;
const startTime = (viewRangeStart / stepLength) * stepLength;
for (let time = startTime; time <= viewRangeEnd; time += stepLength) {
const xpos = Number(time - viewRangeStart) * zoomFactor;
if (xpos >= 0 && xpos < canvasDisplayWidth) {
const rangeStart = viewport ? this.unitController.worldRange.start + this.unitController.offset : this.unitController.viewRange.start + this.unitController.offset;
const rangeEnd = viewport ? this.unitController.worldRange.end + this.unitController.offset : this.unitController.viewRange.end + this.unitController.offset;
const startTime = (rangeStart / stepLength) * stepLength;
for (let time = startTime; time <= rangeEnd; time += stepLength) {
const xpos = Number(time - rangeStart) * zoomFactor;
const worldRatio = this.unitController.worldRangeLength / this.unitController.viewRangeLength;
const xposEnd = canvasDisplayWidth * Number(worldRatio);
const viewportCondition = xpos >= 0 && xpos < xposEnd;
const notViewportCondition = xpos >= 0 && xpos < canvasDisplayWidth;
const shouldContinue = (viewport && viewportCondition) || (!viewport && notViewportCondition);
if (shouldContinue) {
const labelCenter = {
x: xpos,
y: this._options.position.y
Expand All @@ -110,11 +115,11 @@ export class TimeGraphAxisScale extends TimeGraphComponent<null> {
x: xpos,
y: this.getVerticalLineYPosition(lineStyle(label).lineHeight)
};

this.vline({
position: verticalLinePosition,
height: lineStyle(label).lineHeight,
color: lineColor
color: lineColor
});
}
}
Expand Down Expand Up @@ -149,13 +154,13 @@ export class TimeGraphAxisScale extends TimeGraphComponent<null> {
private getVerticalLineYPosition(lineHeight: number) {
if (this._options.verticalAlign === 'bottom') {
return this._options.height - lineHeight;
}
}

// By default the tick will be at the top
return 0;
}

private getTextPosition(labelCenter: {x: number, y: number}, textElement: PIXI.Text, lineStyle: (label: string | undefined) => { lineHeight: number }): {x: number, y: number}{
private getTextPosition(labelCenter: { x: number, y: number }, textElement: PIXI.Text, lineStyle: (label: string | undefined) => { lineHeight: number }): { x: number, y: number } {
const xPosition = labelCenter.x - (textElement.width / 2);
let yPosition = labelCenter.y + lineStyle(textElement.text).lineHeight;

Expand Down
2 changes: 1 addition & 1 deletion timeline-chart/src/components/time-graph-grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ export class TimeGraphGrid extends TimeGraphAxisScale {
}

render(): void {
this.renderVerticalLines(false, this._options.lineColor || 0xdddddd, () => ({ lineHeight: this.stateController.canvasDisplayHeight }));
this.renderVerticalLines(false, this._options.lineColor || 0xdddddd, () => ({ lineHeight: this.stateController.canvasDisplayHeight }), true);
}
}
11 changes: 5 additions & 6 deletions timeline-chart/src/layer/time-graph-chart-arrows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ export class TimeGraphChartArrows extends TimeGraphChartLayer {

protected arrows: Map<TimelineChart.TimeGraphArrow, TimeGraphArrowComponent>;
protected rowIds: number[] = [];
private _updateHandler: { (): void; (viewRange: TimelineChart.TimeGraphRange): void; (viewRange: TimelineChart.TimeGraphRange): void; };
private _updateHandler: { (): void; (worldRange: TimelineChart.TimeGraphRange): void; (worldRange: TimelineChart.TimeGraphRange): void; };

protected afterAddToContainer() {
this._updateHandler = (): void => this.update();
this.unitController.onViewRangeChanged(this._updateHandler);
this.stateController.onWorldRender(this._updateHandler);

this.rowController.onVerticalOffsetChangedHandler(verticalOffset => {
this.layer.position.y = -verticalOffset;
Expand All @@ -24,13 +24,12 @@ export class TimeGraphChartArrows extends TimeGraphChartLayer {
if (sourceIndex === -1 || destinationIndex === -1) {
return undefined;
}
const relativeStartPosition = arrow.range.start - this.unitController.viewRange.start;
const start: TimeGraphElementPosition = {
x: this.getPixel(relativeStartPosition),
x: this.getWorldPixel(arrow.range.start),
y: (sourceIndex * this.rowController.rowHeight) + (this.rowController.rowHeight / 2)
}
const end: TimeGraphElementPosition = {
x: this.getPixel(relativeStartPosition + arrow.range.end - arrow.range.start),
x: this.getWorldPixel(arrow.range.end),
y: (destinationIndex * this.rowController.rowHeight) + (this.rowController.rowHeight / 2)
}
return { start, end };
Expand Down Expand Up @@ -83,7 +82,7 @@ export class TimeGraphChartArrows extends TimeGraphChartLayer {

destroy() : void {
if (this.unitController) {
this.unitController.removeViewRangeChangedHandler(this._updateHandler);
this.stateController.removeWorldRenderHandler(this._updateHandler);
}
super.destroy();
}
Expand Down
8 changes: 4 additions & 4 deletions timeline-chart/src/layer/time-graph-chart-cursors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export class TimeGraphChartCursors extends TimeGraphChartLayer {
}
};
this.onCanvasEvent('mousedown', this._mouseDownHandler);
this.unitController.onViewRangeChanged(this._updateHandler);
this.stateController.onWorldRender(this._updateHandler);
this.unitController.onSelectionRangeChange(this._updateHandler);
this.update();
}
Expand Down Expand Up @@ -224,8 +224,8 @@ export class TimeGraphChartCursors extends TimeGraphChartLayer {

update() {
if (this.unitController.selectionRange) {
const firstCursorPosition = this.getPixel(this.unitController.selectionRange.start - this.unitController.viewRange.start);
const secondCursorPosition = this.getPixel(this.unitController.selectionRange.end - this.unitController.viewRange.start);
const firstCursorPosition = this.getWorldPixel(this.unitController.selectionRange.start);
const secondCursorPosition = this.getWorldPixel(this.unitController.selectionRange.end);
const firstCursorOptions = {
color: this.color,
height: this.stateController.canvasDisplayHeight,
Expand Down Expand Up @@ -268,7 +268,7 @@ export class TimeGraphChartCursors extends TimeGraphChartLayer {

destroy() : void {
if (this.unitController) {
this.unitController.removeViewRangeChangedHandler(this._updateHandler);
this.stateController.removeWorldRenderHandler(this._updateHandler);
this.unitController.removeSelectionRangeChangedHandler(this._updateHandler);
}
if (this._mouseDownHandler) {
Expand Down
8 changes: 4 additions & 4 deletions timeline-chart/src/layer/time-graph-chart-grid.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { TimeGraphLayer } from "./time-graph-layer";
import { TimeGraphViewportLayer } from "./time-graph-viewport-layer";
import { TimeGraphGrid } from "../components/time-graph-grid";
import { TimelineChart } from "../time-graph-model";
import { TimeGraphAxisLayerOptions } from "./time-graph-axis";

export class TimeGraphChartGrid extends TimeGraphLayer {
export class TimeGraphChartGrid extends TimeGraphViewportLayer {

protected gridComponent: TimeGraphGrid;
private _updateHandler: { (): void; (viewRange: TimelineChart.TimeGraphRange): void; (viewRange: TimelineChart.TimeGraphRange): void; (selectionRange: TimelineChart.TimeGraphRange): void; };;
Expand All @@ -21,7 +21,7 @@ export class TimeGraphChartGrid extends TimeGraphLayer {
}, this.rowHeight, this.unitController, this.stateController);
this.addChild(this.gridComponent);
this._updateHandler = (): void => this.update();
this.unitController.onViewRangeChanged(this._updateHandler);
this.stateController.onWorldRender(this._updateHandler);
}

update(opts?: TimeGraphAxisLayerOptions) {
Expand All @@ -30,7 +30,7 @@ export class TimeGraphChartGrid extends TimeGraphLayer {

destroy() : void {
if (this.unitController) {
this.unitController.removeViewRangeChangedHandler(this._updateHandler);
this.stateController.removeWorldRenderHandler(this._updateHandler);
this.unitController.removeSelectionRangeChangedHandler(this._updateHandler);
}
super.destroy();
Expand Down
8 changes: 4 additions & 4 deletions timeline-chart/src/layer/time-graph-chart-layer.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { TimeGraphLayer } from "./time-graph-layer";
import { TimeGraphRowController } from "../time-graph-row-controller";
import { TimeGraphViewportLayer } from "./time-graph-viewport-layer";

export abstract class TimeGraphChartLayer extends TimeGraphLayer {
export abstract class TimeGraphChartLayer extends TimeGraphViewportLayer {

constructor(id: string, protected rowController: TimeGraphRowController){
constructor(id: string, protected rowController: TimeGraphRowController) {
super(id);
}

}
20 changes: 8 additions & 12 deletions timeline-chart/src/layer/time-graph-chart-selection-range.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { TimeGraphRectangle } from "../components/time-graph-rectangle";
import { TimelineChart } from "../time-graph-model";
import { TimeGraphLayer } from "./time-graph-layer";
import { TimeGraphViewportLayer } from "./time-graph-viewport-layer";

export class TimeGraphChartSelectionRange extends TimeGraphLayer {
export class TimeGraphChartSelectionRange extends TimeGraphViewportLayer {
protected selectionRange?: TimeGraphRectangle;
protected color: number = 0x0000ff;
private _viewRangeUpdateHandler: { (): void; (viewRange: TimelineChart.TimeGraphRange): void; (viewRange: TimelineChart.TimeGraphRange): void; };
private _updateHandler: { (): void; (selectionRange: TimelineChart.TimeGraphRange): void; (selectionRange: TimelineChart.TimeGraphRange): void; };

constructor(id: string, style?: { color?: number }) {
Expand All @@ -17,8 +16,8 @@ export class TimeGraphChartSelectionRange extends TimeGraphLayer {

protected updateScaleAndPosition() {
if (this.unitController.selectionRange && this.selectionRange) {
const firstCursorPosition = this.getPixel(this.unitController.selectionRange.start - this.unitController.viewRange.start);
const width = this.getPixel(this.unitController.selectionRange.end - this.unitController.selectionRange.start)
const firstCursorPosition = this.getWorldPixel(this.unitController.selectionRange.start);
const width = this.getPixel(this.unitController.selectionRange.end - this.unitController.selectionRange.start);
this.selectionRange.update({
position: {
x: firstCursorPosition,
Expand All @@ -31,12 +30,9 @@ export class TimeGraphChartSelectionRange extends TimeGraphLayer {
}

protected afterAddToContainer() {
this._viewRangeUpdateHandler = () => {
this.updateScaleAndPosition();
};

this._updateHandler = (): void => this.update();
this.unitController.onViewRangeChanged(this._viewRangeUpdateHandler);
this.stateController.onWorldRender(this._updateHandler);
this.unitController.onSelectionRangeChange(this._updateHandler);
this.update();
}
Expand All @@ -48,8 +44,8 @@ export class TimeGraphChartSelectionRange extends TimeGraphLayer {

update() {
if (this.unitController.selectionRange) {
const firstCursorPosition = this.getPixel(this.unitController.selectionRange.start - this.unitController.viewRange.start);
const secondCursorPosition = this.getPixel(this.unitController.selectionRange.end - this.unitController.viewRange.start);
const firstCursorPosition = this.getWorldPixel(this.unitController.selectionRange.start);
const secondCursorPosition = this.getWorldPixel(this.unitController.selectionRange.end);
if (secondCursorPosition !== firstCursorPosition) {
if (!this.selectionRange) {
this.selectionRange = new TimeGraphRectangle({
Expand Down Expand Up @@ -83,7 +79,7 @@ export class TimeGraphChartSelectionRange extends TimeGraphLayer {

destroy() : void {
if (this.unitController) {
this.unitController.removeViewRangeChangedHandler(this._viewRangeUpdateHandler);
this.stateController.removeWorldRenderHandler(this._updateHandler);
this.unitController.removeSelectionRangeChangedHandler(this._updateHandler);
}
super.destroy();
Expand Down
Loading

0 comments on commit 16e8148

Please sign in to comment.