Skip to content

Commit

Permalink
working zoom
Browse files Browse the repository at this point in the history
  • Loading branch information
joel-wenzel committed Jun 29, 2021
1 parent e9a91b1 commit b24c468
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 56 deletions.
9 changes: 9 additions & 0 deletions projects/ng-flowchart/src/lib/model/flow.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ export namespace NgFlowchart {

/** Should the canvas be centered when a resize is detected? */
centerOnResize?: boolean = true;

/** Canvas zoom options. Defaults to mouse wheel zoom */
zoom?: {
mode: 'WHEEL' | 'NONE'
rescaleOnResize: boolean
} = {
mode: 'WHEEL',
rescaleOnResize: true
}
}

export type DropEvent = {
Expand Down
83 changes: 63 additions & 20 deletions projects/ng-flowchart/src/lib/ng-flowchart-canvas.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ import { StepManagerService } from './services/step-manager.service';
CanvasRendererService
]
})
export class NgFlowchartCanvasDirective implements OnInit, OnDestroy, AfterViewInit {
export class NgFlowchartCanvasDirective implements OnInit, OnDestroy, AfterViewInit {

@HostListener('drop', ['$event'])
protected onDrop(event: DragEvent) {
if (this._disabled) { return; }

// its possible multiple canvases exist so make sure we only move/drop on the closest one
const closestCanvasId = (event.target as HTMLElement).closest('.ngflowchart-canvas-content')?.id
if(this._id !== closestCanvasId) {
if (this._id !== closestCanvasId) {
return;
}

const type = event.dataTransfer.getData('type');
if ('FROM_CANVAS' == type) {
this.canvas.moveStep(event, event.dataTransfer.getData('id'));
Expand All @@ -54,7 +54,16 @@ export class NgFlowchartCanvasDirective implements OnInit, OnDestroy, AfterViewI
if (this._options.centerOnResize) {
this.canvas.reRender(true);
}
if(this._options.zoom.rescaleOnResize) {

}
}

@HostListener('wheel', ['$event'])
protected onZoom(event) {
if (this._options.zoom.mode === 'WHEEL') {
this.adjustScale(event)
}
}

@Input('ngFlowchartCallbacks')
Expand All @@ -74,26 +83,32 @@ export class NgFlowchartCanvasDirective implements OnInit, OnDestroy, AfterViewI
@HostBinding('attr.disabled')
set disabled(val: boolean) {
this._disabled = val !== false;
if(this.canvas) {
if (this.canvas) {
this.canvas._disabled = this._disabled;
}
}

get disabled() {
return this._disabled;
}

_disabled: boolean = false;
_id: string = null
private _disabled: boolean = false;
private _scaleVal: number = 1;
private _id: string = null
private canvasContent: HTMLElement;
private scaleDebounceTimer

constructor(
protected canvasEle: ElementRef<HTMLElement>,
private viewContainer: ViewContainerRef,
private canvas: NgFlowchartCanvasService,
private optionService: OptionsService
) {

this.canvasEle.nativeElement.classList.add(CONSTANTS.CANVAS_CLASS);
this._id = this.createCanvasContent(this.viewContainer);

this.canvasContent = this.createCanvasContent(this.viewContainer);
this._id = this.canvasContent.id

}

ngOnInit() {
Expand All @@ -103,35 +118,32 @@ export class NgFlowchartCanvasDirective implements OnInit, OnDestroy, AfterViewI
}

this.canvas._disabled = this._disabled;

}

ngAfterViewInit() {

}

ngOnDestroy() {
for(let i = 0 ; i < this.viewContainer.length; i++){

for (let i = 0; i < this.viewContainer.length; i++) {
this.viewContainer.remove(i)
}
this.canvasEle.nativeElement.remove()
this.viewContainer.element.nativeElement.remove()
// this.canvas = undefined
// this.canvasEle = undefined
// this.optionService = undefined
this.viewContainer = undefined
}

private createCanvasContent(viewContainer: ViewContainerRef): string {
private createCanvasContent(viewContainer: ViewContainerRef): HTMLElement {
const canvasId = 'c' + Date.now();

let canvasEle = viewContainer.element.nativeElement as HTMLElement;
let canvasContent = document.createElement('div');
canvasContent.id = canvasId;
canvasContent.classList.add(CONSTANTS.CANVAS_CONTENT_CLASS);
canvasEle.appendChild(canvasContent);
return canvasId
return canvasContent
}

/**
Expand All @@ -140,4 +152,35 @@ export class NgFlowchartCanvasDirective implements OnInit, OnDestroy, AfterViewI
public getFlow() {
return new NgFlowchart.Flow(this.canvas);
}

private adjustScale(event) {

if (this.canvas.flow.hasRoot()) {
event.preventDefault();
// scale down / zoom out

if(event.deltaY > 0) {
this._scaleVal -= this._scaleVal * .1
}
// scale up / zoom in
else if(event.deltaY < 0) {
this._scaleVal += this._scaleVal * .1
}
const minDimAdjust = `${1/this._scaleVal * 100}%`

this.canvasContent.style.transform = `scale(${this._scaleVal})`;
this.canvasContent.style.minHeight = minDimAdjust
this.canvasContent.style.minWidth = minDimAdjust
this.canvasContent.style.transformOrigin = 'top left'
this.canvasContent.classList.add('scaling')

this.canvas.setScale(this._scaleVal)
this.canvas.reRender(true)

this.scaleDebounceTimer && clearTimeout(this.scaleDebounceTimer)
this.scaleDebounceTimer = setTimeout(() => {
this.canvasContent.classList.remove('scaling')
}, 300)
}
};
}
4 changes: 4 additions & 0 deletions projects/ng-flowchart/src/lib/ng-flowchart-canvas.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ export class NgFlowchartCanvasService {

}

public setScale(scale: number) {
this.renderer.setScale(scale)
}

public init(view: ViewContainerRef) {
this.viewContainer = view;
this.renderer.init(view);
Expand Down
116 changes: 82 additions & 34 deletions projects/ng-flowchart/src/lib/services/canvas-renderer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@ export type DropProximity = {
export class CanvasRendererService {
private viewContainer: ViewContainerRef;

private scale: number = 1;

constructor(
private options: OptionsService
) {

}

public setScale(scale: number) {
this.scale = scale;
}

public init(viewContainer: ViewContainerRef) {
this.viewContainer = viewContainer;
}
Expand All @@ -35,10 +41,16 @@ export class CanvasRendererService {
}

public updatePosition(step: NgFlowchartStepComponent, dragEvent: DragEvent) {
const relativeXY = this.getRelativeXY(dragEvent);
let relativeXY = this.getRelativeXY(dragEvent);

relativeXY = relativeXY.map(coord => coord / this.scale)
step.zsetPosition(relativeXY, true);
}

private getStepGap() {
return this.options.options.stepGap;
}

private renderChildTree(rootNode: NgFlowchartStepComponent, rootRect: Partial<DOMRect>, canvasRect: DOMRect) {
//the rootNode passed in is already rendered. just need to render its children /subtree

Expand All @@ -47,22 +59,27 @@ export class CanvasRendererService {
}

//top of the child row is simply the relative bottom of the root + stepGap
const childYTop = (rootRect.bottom - canvasRect.top) + this.options.options.stepGap;
const rootXCenter = (rootRect.left - canvasRect.left) + (rootRect.width / 2);
const childYTop = (rootRect.bottom - canvasRect.top * this.scale) + this.getStepGap();

const rootWidth = rootRect.width / this.scale

const rootXCenter = (rootRect.left - canvasRect.left) + (rootWidth / 2);


//get the width of the child trees
let childTreeWidths = {};
let totalTreeWidth = 0;

rootNode.children.forEach(child => {
let totalChildWidth = child.getNodeTreeWidth(this.options.options.stepGap);
let totalChildWidth = child.getNodeTreeWidth(this.getStepGap());
totalChildWidth = totalChildWidth / this.scale
childTreeWidths[child.nativeElement.id] = totalChildWidth;

totalTreeWidth += totalChildWidth;
});

//add length for stepGaps between child trees
totalTreeWidth += (rootNode.children.length - 1) * this.options.options.stepGap;
totalTreeWidth += (rootNode.children.length - 1) * this.getStepGap();

//if we have more than 1 child, we want half the extent on the left and half on the right
let leftXTree = rootXCenter - (totalTreeWidth / 2);
Expand All @@ -72,17 +89,21 @@ export class CanvasRendererService {
let childExtent = childTreeWidths[child.nativeElement.id];

let childLeft = leftXTree + (childExtent / 2) - (child.nativeElement.offsetWidth / 2);


child.zsetPosition([childLeft, childYTop]);

const currentChildRect = child.getCurrentRect(canvasRect);

const childWidth = currentChildRect.width / this.scale

child.zdrawArrow(
[rootXCenter, (rootRect.bottom - canvasRect.top)],
[currentChildRect.left + currentChildRect.width / 2 - canvasRect.left, currentChildRect.top - canvasRect.top]
[rootXCenter, (rootRect.bottom - canvasRect.top * this.scale)],
[currentChildRect.left + childWidth / 2 - canvasRect.left, currentChildRect.top - canvasRect.top]
);

this.renderChildTree(child, currentChildRect, canvasRect);
leftXTree += childExtent + this.options.options.stepGap;
leftXTree += childExtent + this.getStepGap();
})

}
Expand Down Expand Up @@ -113,34 +134,34 @@ export class CanvasRendererService {

private adjustDimensions(flow: CanvasFlow, canvasRect: DOMRect) {

let maxRight = 0;
let maxBottom = 0;
// let maxRight = 0;
// let maxBottom = 0;

//TODO this can be better
flow.steps.forEach(
ele => {
let rect = ele.getCurrentRect(canvasRect);
maxRight = Math.max(rect.right, maxRight);
maxBottom = Math.max(rect.bottom, maxBottom);
}
);
// //TODO this can be better
// flow.steps.forEach(
// ele => {
// let rect = ele.getCurrentRect(canvasRect);
// maxRight = Math.max(rect.right, maxRight);
// maxBottom = Math.max(rect.bottom, maxBottom);
// }
// );



const widthDiff = canvasRect.width - (maxRight - canvasRect.left);
if (widthDiff < 100) {
this.getCanvasContentElement().style.minWidth = `${canvasRect.width + 200}px`;
if (this.options.options.centerOnResize) {
//if we add width, rerender canvas in the middle
this.render(flow, true);
}
// const widthDiff = canvasRect.width - (maxRight - canvasRect.left);
// if (widthDiff < 100) {
// this.getCanvasContentElement().style.minWidth = `${canvasRect.width + 200}px`;
// if (this.options.options.centerOnResize) {
// //if we add width, rerender canvas in the middle
// this.render(flow, true);
// }

}
// }

const heightDiff = canvasRect.height - (maxBottom - canvasRect.top);
if (heightDiff < 100) {
this.getCanvasContentElement().style.minHeight = `${canvasRect.height + 200}px`;
}
// const heightDiff = canvasRect.height - (maxBottom - canvasRect.top);
// if (heightDiff < 100) {
// this.getCanvasContentElement().style.minHeight = `${canvasRect.height + 200}px`;
// }

}

Expand Down Expand Up @@ -267,7 +288,7 @@ export class CanvasRendererService {
}

private setRootPosition(step: NgFlowchartStepComponent, dragEvent?: DragEvent) {

if (!dragEvent) {
const canvasTop = this.getCanvasTopCenterPosition(step.nativeElement);
step.zsetPosition(canvasTop, true)
Expand Down Expand Up @@ -303,10 +324,11 @@ export class CanvasRendererService {
const canvasRect = this.getCanvasContentElement().getBoundingClientRect();
const rootElementHeight = htmlRootElement.getBoundingClientRect().height
const yCoord = rootElementHeight / 2 + this.options.options.stepGap

const scaleYOffset = (1 - this.scale) * 100

return [
canvasRect.width / 2,
yCoord
canvasRect.width / (this.scale * 2),
yCoord + scaleYOffset
]
}

Expand All @@ -324,5 +346,31 @@ export class CanvasRendererService {
return canvasContent as HTMLElement;
}

// public scaleUp() {
// const minDimAdjust = `${1/this._scaleVal * 100}%`

// this.canvasContent.style.transform = `scale(${this._scaleVal})`;
// this.canvasContent.style.minHeight = minDimAdjust
// this.canvasContent.style.minWidth = minDimAdjust
// this.canvasContent.style.transformOrigin = 'top left'
// this.canvasContent.classList.add('scaling')

// this.canvas.setScale(this._scaleVal)
// this.canvas.reRender(true)

// this.scaleDebounceTimer && clearTimeout(this.scaleDebounceTimer)
// this.scaleDebounceTimer = setTimeout(() => {
// this.canvasContent.classList.remove('scaling')
// }, 300)
// }

// public scaleDown() {

// }

// private scale() {

// }


}
Loading

0 comments on commit b24c468

Please sign in to comment.