Skip to content

Commit

Permalink
[FEAT] zoom to mouse pointer (#774)
Browse files Browse the repository at this point in the history
[FEAT] zoom to mouse pointer (#774)
  • Loading branch information
aibcmars authored Oct 16, 2020
1 parent 873c1b0 commit 15c4eea
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 8 deletions.
67 changes: 60 additions & 7 deletions src/component/mxgraph/MxGraphConfigurator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ declare const mxClient: typeof mxgraph.mxClient;
* <li>markers
*/
export default class MxGraphConfigurator {
private readonly graph: mxGraph;
private readonly graph: BpmnMxGraph;

constructor(readonly container: HTMLElement) {
this.graph = new mxGraph(container);
this.graph = new BpmnMxGraph(container);
}

public configure(options?: BpmnVisualizationOptions): mxGraph {
Expand Down Expand Up @@ -91,17 +91,70 @@ export default class MxGraphConfigurator {
// only the ctrl key or the meta key on mac
const isZoomWheelEvent = (evt.ctrlKey || (mxClient.IS_MAC && evt.metaKey)) && !evt.altKey && !evt.shiftKey;
if (isZoomWheelEvent) {
this.zoom(up);
this.graph.performZoom(up, evt);
mxEvent.consume(evt);
}
}, this.container);
}
}

class BpmnMxGraph extends mxGraph {
private cumulativeZoomFactor = 1;

constructor(readonly container: HTMLElement) {
super(container);
}

// override fit to set initial cumulativeZoomFactor
fit(order: number, keepOrigin?: boolean, margin?: number, enabled?: boolean, ignoreWidth?: boolean, ignoreHeight?: boolean, maxHeight?: number): number {
const scale = super.fit(order, keepOrigin, margin, enabled, ignoreWidth, ignoreHeight, maxHeight);
this.cumulativeZoomFactor = scale;
return scale;
}

// solution inspired by https://github.com/algenty/grafana-flowcharting/blob/0.9.0/src/graph_class.ts#L1254
public performZoom(up: boolean, evt: MouseEvent): void {
const rect = this.container.getBoundingClientRect();
const x = evt.clientX - rect.left;
const y = evt.clientY - rect.top;
this.zoomTo(null, null, up, x, y);
}

private zoom(zoomIn: boolean): void {
if (zoomIn) {
this.graph.zoomIn();
zoomTo(scale: number, center?: boolean, up?: boolean, offsetX?: number, offsetY?: number): void {
if (scale === null) {
const [newScale, dx, dy] = this.getScaleAndTranslationDeltas(up, offsetX, offsetY);
this.view.scaleAndTranslate(newScale, this.view.translate.x + dx, this.view.translate.y + dy);
} else {
this.graph.zoomOut();
super.zoomTo(scale, center);
}
}

private getScaleAndTranslationDeltas(up: boolean, offsetX: number, offsetY: number): [number, number, number] {
let dx = offsetX * 2;
let dy = offsetY * 2;
const [factor, scale] = this.calculateFactorAndScale(up);
[dx, dy] = this.calculateTranslationDeltas(factor, scale, dx, dy);
return [scale, dx, dy];
}

private calculateTranslationDeltas(factor: number, scale: number, dx: number, dy: number): [number, number] {
if (factor > 1) {
const f = (factor - 1) / (scale * 2);
dx *= -f;
dy *= -f;
} else {
const f = (1 / factor - 1) / (this.view.scale * 2);
dx *= f;
dy *= f;
}
return [dx, dy];
}

private calculateFactorAndScale(up: boolean): [number, number] {
this.cumulativeZoomFactor *= up ? 1.2 : 0.8;
let factor = this.cumulativeZoomFactor / this.view.scale;
const scale = Math.round(this.view.scale * factor * 100) / 100;
factor = scale / this.view.scale;
return [factor, scale];
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test/e2e/bpmn.navigation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ describe('diagram navigation', () => {
it.each(['zoom in', 'zoom out'])(`ctrl + mouse: %s`, async (zoom: string) => {
const deltaX = zoom === 'zoom in' ? -100 : 100;
// simulate mouse+ctrl zoom
await page.mouse.move(viewportCenterX, viewportCenterY);
await page.mouse.move(viewportCenterX + 200, viewportCenterY);
await page.keyboard.down('Control');
await (<MouseWithWheel>page.mouse).wheel({ deltaX: deltaX });

Expand Down

0 comments on commit 15c4eea

Please sign in to comment.