diff --git a/timeline-chart/src/components/time-graph-axis-scale.ts b/timeline-chart/src/components/time-graph-axis-scale.ts index 1e69839..d8048b4 100644 --- a/timeline-chart/src/components/time-graph-axis-scale.ts +++ b/timeline-chart/src/components/time-graph-axis-scale.ts @@ -28,9 +28,18 @@ export class TimeGraphAxisScale extends TimeGraphComponent { protected addEvents() { const mouseMove = _.throttle(event => { if (this.mouseIsDown) { - const delta = event.data.global.y - this.mouseStartY; + /** + Zoom around MousePosition on drag up/down + left here as an additional option + to be added later + */ + // const delta = event.data.global.y - this.mouseStartY; + // const zoomStep = (delta / 100); + // this.zoomAroundMousePointerOnDrag(zoomStep); + + const delta = event.data.global.x - this.mouseStartX; const zoomStep = (delta / 100); - this.zoom(zoomStep); + this.zoomAroundLeftViewBorder(zoomStep); } }, 40); this.addEvent('mousedown', event => { @@ -54,7 +63,10 @@ export class TimeGraphAxisScale extends TimeGraphComponent { const maxSteps = canvasDisplayWidth / minCanvasStepWidth; const realStepLength = viewRangeLength / maxSteps; const log = Math.log10(realStepLength); - const logRounded = Math.round(log); + let logRounded = Math.round(log); + if(this.unitController.discreteScale){ + logRounded = Math.abs(logRounded); + } const normalizedStepLength = Math.pow(10, logRounded); const residual = realStepLength / normalizedStepLength; const steps = this.unitController.scaleSteps || [1, 1.5, 2, 2.5, 5, 10]; @@ -112,7 +124,21 @@ export class TimeGraphAxisScale extends TimeGraphComponent { this.renderVerticalLines(10, this._options.lineColor || 0x000000); } - zoom(zoomStep: number) { + zoomAroundLeftViewBorder(zoomStep: number) { + const oldViewRangeLength = this.oldViewRange.end - this.oldViewRange.start; + const newViewRangeLength = oldViewRangeLength / (1 + (zoomStep)); + let start = this.oldViewRange.start; + let end = start + newViewRangeLength; + if (end > this.unitController.absoluteRange) { + end = this.unitController.absoluteRange; + } + this.unitController.viewRange = { + start, + end + } + } + + zoomAroundMousePointerOnDrag(zoomStep: number) { const oldViewRangeLength = this.oldViewRange.end - this.oldViewRange.start; const newViewRangeLength = oldViewRangeLength / (1 + (zoomStep)); const normZoomFactor = newViewRangeLength / oldViewRangeLength; diff --git a/timeline-chart/src/components/time-graph-row-element.ts b/timeline-chart/src/components/time-graph-row-element.ts index a4d1a1e..26289f6 100644 --- a/timeline-chart/src/components/time-graph-row-element.ts +++ b/timeline-chart/src/components/time-graph-row-element.ts @@ -21,24 +21,24 @@ export class TimeGraphRowElement extends TimeGraphComponent { protected _model: TimelineChart.TimeGraphRowElementModel, protected range: TimelineChart.TimeGraphRange, protected _row: TimeGraphRow, - style: TimeGraphRowElementStyle = { color: 0xfffa66, height: 14 }, + protected _style: TimeGraphRowElementStyle = { color: 0xfffa66, height: 14 }, displayObject?: PIXI.Graphics ) { super(id, displayObject); - this.height = style.height || 14; + this.height = _style.height || 14; this.position = { x: this.range.start, y: this._row.position.y + ((this.row.height - this.height) / 2) }; const width = this.range.end - this.range.start; this._options = { - color: style.color, + color: _style.color, height: this.height, position: this.position, width, borderRadius: 2, - borderWidth: style.borderWidth || 0, - borderColor: style.borderColor || 0x000000 + borderWidth: _style.borderWidth || 0, + borderColor: _style.borderColor || 0x000000 }; } @@ -50,6 +50,10 @@ export class TimeGraphRowElement extends TimeGraphComponent { return this._row; } + get style(){ + return this._style; + } + set style(style: TimeGraphRowElementStyle) { if (style.color !== undefined) { this._options.color = style.color; diff --git a/timeline-chart/src/layer/time-graph-axis.ts b/timeline-chart/src/layer/time-graph-axis.ts index fa82dd7..7489964 100644 --- a/timeline-chart/src/layer/time-graph-axis.ts +++ b/timeline-chart/src/layer/time-graph-axis.ts @@ -5,7 +5,7 @@ import * as _ from "lodash"; export class TimeGraphAxis extends TimeGraphLayer { protected scaleComponent: TimeGraphAxisScale; - + protected controlKeyDown: boolean; constructor(id: string, protected style?: { color?: number, lineColor?: number }) { super(id); @@ -14,7 +14,7 @@ export class TimeGraphAxis extends TimeGraphLayer { protected getOptions() { let color; let lineColor; - if(this.style){ + if (this.style) { color = this.style.color; lineColor = this.style.lineColor; } @@ -31,19 +31,58 @@ export class TimeGraphAxis extends TimeGraphLayer { } protected afterAddToContainer() { + this.controlKeyDown = false + document.addEventListener('keydown', (event: KeyboardEvent) => { + this.controlKeyDown = event.ctrlKey; + }); + document.addEventListener('keyup', (event: KeyboardEvent) => { + this.controlKeyDown = event.ctrlKey; + }); const mw = _.throttle((ev: WheelEvent) => { - const shiftStep = ev.deltaY; - const oldViewRange = this.unitController.viewRange; - let start = oldViewRange.start + (shiftStep / this.stateController.zoomFactor); - if (start < 0) { - start = 0; - } - let end = start + this.unitController.viewRangeLength; - if (end > this.unitController.absoluteRange) { - start = this.unitController.absoluteRange - this.unitController.viewRangeLength; - end = start + this.unitController.viewRangeLength; + if (this.controlKeyDown) { + // ZOOM AROUND MOUSE POINTER + let newViewRangeLength = this.unitController.viewRangeLength; + let xOffset = 0; + let moveX = false; + if (Math.abs(ev.deltaX) > Math.abs(ev.deltaY)) { + xOffset = -(ev.deltaX / this.stateController.zoomFactor); + moveX = true; + } else { + const zoomPosition = (ev.offsetX / this.stateController.zoomFactor); + const deltaLength = (ev.deltaY / this.stateController.zoomFactor); + newViewRangeLength += deltaLength; + xOffset = ((zoomPosition / this.unitController.viewRangeLength) * deltaLength); + } + let start = this.unitController.viewRange.start - xOffset; + if (start < 0) { + start = 0; + } + let end = start + newViewRangeLength; + if (end > this.unitController.absoluteRange) { + end = this.unitController.absoluteRange; + if (moveX) { + start = end - newViewRangeLength; + } + } + this.unitController.viewRange = { + start, + end + } + } else { + // PANNING + const shiftStep = ev.deltaY; + const oldViewRange = this.unitController.viewRange; + let start = oldViewRange.start + (shiftStep / this.stateController.zoomFactor); + if (start < 0) { + start = 0; + } + let end = start + this.unitController.viewRangeLength; + if (end > this.unitController.absoluteRange) { + start = this.unitController.absoluteRange - this.unitController.viewRangeLength; + end = start + this.unitController.viewRangeLength; + } + this.unitController.viewRange = { start, end } } - this.unitController.viewRange = { start, end } return false; }); this.onCanvasEvent('mousewheel', mw); diff --git a/timeline-chart/src/layer/time-graph-chart.ts b/timeline-chart/src/layer/time-graph-chart.ts index 311a095..3ff70f7 100644 --- a/timeline-chart/src/layer/time-graph-chart.ts +++ b/timeline-chart/src/layer/time-graph-chart.ts @@ -36,6 +36,7 @@ export class TimeGraphChart extends TimeGraphChartLayer { protected fetching: boolean; protected shiftKeyDown: boolean; + protected ctrlKeyDown: boolean; constructor(id: string, protected providers: TimeGraphChartProviders, @@ -46,37 +47,46 @@ export class TimeGraphChart extends TimeGraphChartLayer { } protected afterAddToContainer() { - this.shiftKeyDown = false + this.shiftKeyDown = false; + this.ctrlKeyDown = false; document.addEventListener('keydown', (event: KeyboardEvent) => { this.shiftKeyDown = event.shiftKey; + this.ctrlKeyDown = event.ctrlKey; }); document.addEventListener('keyup', (event: KeyboardEvent) => { this.shiftKeyDown = event.shiftKey; + this.ctrlKeyDown = event.ctrlKey; }); const mw = (ev: WheelEvent) => { - if (this.shiftKeyDown) { - const shiftStep = ev.deltaY; - let verticalOffset = this.rowController.verticalOffset + shiftStep; - if (verticalOffset < 0) { - verticalOffset = 0; + if (this.ctrlKeyDown) { + let newViewRangeLength = this.unitController.viewRangeLength; + let xOffset = 0; + let moveX = false; + const zoomPosition = (ev.offsetX / this.stateController.zoomFactor); + const deltaLength = (ev.deltaY / this.stateController.zoomFactor); + newViewRangeLength += deltaLength; + xOffset = ((zoomPosition / this.unitController.viewRangeLength) * deltaLength); + let start = this.unitController.viewRange.start - xOffset; + if (start < 0) { + start = 0; } - if (this.rowController.totalHeight - verticalOffset <= this.stateController.canvasDisplayHeight) { - verticalOffset = this.rowController.totalHeight - this.stateController.canvasDisplayHeight; + let end = start + newViewRangeLength; + if (end > this.unitController.absoluteRange) { + end = this.unitController.absoluteRange; + if (moveX) { + start = end - newViewRangeLength; + } } - this.rowController.verticalOffset = verticalOffset; - } else { + this.unitController.viewRange = { + start, + end + } + } else if (this.shiftKeyDown) { let newViewRangeLength = this.unitController.viewRangeLength; let xOffset = 0; let moveX = false; - if (Math.abs(ev.deltaX) > Math.abs(ev.deltaY)) { - xOffset = -(ev.deltaX / this.stateController.zoomFactor); - moveX = true; - } else { - const zoomPosition = (ev.offsetX / this.stateController.zoomFactor); - const deltaLength = (ev.deltaY / this.stateController.zoomFactor); - newViewRangeLength += deltaLength; - xOffset = ((zoomPosition / this.unitController.viewRangeLength) * deltaLength); - } + xOffset = -(ev.deltaY / this.stateController.zoomFactor); + moveX = true; let start = this.unitController.viewRange.start - xOffset; if (start < 0) { start = 0; @@ -92,6 +102,16 @@ export class TimeGraphChart extends TimeGraphChartLayer { start, end } + } else { + const shiftStep = ev.deltaY; + let verticalOffset = this.rowController.verticalOffset + shiftStep; + if (verticalOffset < 0) { + verticalOffset = 0; + } + if (this.rowController.totalHeight - verticalOffset <= this.stateController.canvasDisplayHeight) { + verticalOffset = this.rowController.totalHeight - this.stateController.canvasDisplayHeight; + } + this.rowController.verticalOffset = verticalOffset; } ev.preventDefault(); } @@ -208,8 +228,8 @@ export class TimeGraphChart extends TimeGraphChartLayer { } protected createNewRowElement(rowElementModel: TimelineChart.TimeGraphRowElementModel, rowComponent: TimeGraphRow) { - const start = this.getPixels(rowElementModel.range.start); - const end = this.getPixels(rowElementModel.range.end); + const start = this.getPixels(rowElementModel.range.start - this.unitController.viewRange.start); + const end = this.getPixels(rowElementModel.range.end - this.unitController.viewRange.start); const range: TimelineChart.TimeGraphRange = { start, end @@ -317,6 +337,7 @@ export class TimeGraphChart extends TimeGraphChartLayer { if (row) { const newEl = this.createNewRowElement(model, row); this.removeChild(el); + this.addElementInteractions(newEl); this.addChild(newEl); this.selectRow(newEl.row.model); } diff --git a/timeline-chart/src/time-graph-unit-controller.ts b/timeline-chart/src/time-graph-unit-controller.ts index 827a042..554dcd7 100644 --- a/timeline-chart/src/time-graph-unit-controller.ts +++ b/timeline-chart/src/time-graph-unit-controller.ts @@ -9,6 +9,7 @@ export class TimeGraphUnitController { numberTranslator?: (theNumber: number) => string; scaleSteps?: number[] + discreteScale?: boolean; constructor(public absoluteRange: number, viewRange?: TimelineChart.TimeGraphRange) { this.viewRangeChangedHandlers = [];