Support canvas transformation when dragged, Fixes: #96

This commit is contained in:
ziajka 2018-04-09 10:37:58 +02:00
parent 01f2518323
commit 74e60bd8d0
8 changed files with 98 additions and 38 deletions

View File

@ -84,9 +84,9 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
this.graphContext = new Context(true);
if (this.windowFullSize) {
this.graphContext.setSize(this.getSize());
this.graphContext.size = this.getSize();
} else {
this.graphContext.setSize(new Size(this.width, this.height));
this.graphContext.size = new Size(this.width, this.height);
}
this.graphLayout = new GraphLayout();
@ -113,19 +113,14 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
}
private changeLayout() {
if (this.windowFullSize) {
if (this.parentNativeElement != null) {
this.graphContext.setSize(this.getSize());
}
} else {
if (this.parentNativeElement != null) {
this.graphContext.size = this.getSize();
}
if (this.graphContext != null) {
this.svg
.attr('width', this.graphContext.getSize().width)
.attr('height', this.graphContext.getSize().height);
.attr('width', this.graphContext.size.width)
.attr('height', this.graphContext.size.height);
}
this.graphLayout.setNodes(this.nodes);

View File

@ -1,25 +1,27 @@
import {Size} from "./size";
import {Point} from "./point";
export class Transformation {
constructor(
public x: number,
public y: number,
public k: number
) {}
}
export class Context {
private size: Size;
public transformation: Transformation;
public size: Size;
constructor(private centerZeroZeroPoint = false) {
constructor(public centerZeroZeroPoint = true) {
this.size = new Size(0, 0);
}
public getSize(): Size {
return this.size;
}
public setSize(size: Size): void {
this.size = size;
this.transformation = new Transformation(0, 0, 1);
}
public getZeroZeroTransformationPoint() {
if (this.centerZeroZeroPoint) {
return new Point(this.getSize().width / 2., this.getSize().height / 2.);
return new Point(this.size.width / 2., this.size.height / 2.);
}
return new Point(0, 0);
}

View File

@ -2,6 +2,7 @@ import { Context } from "../models/context";
import { SVGSelection } from "../models/types";
import { MovingTool } from "./moving-tool";
import { TestSVGCanvas } from "../../testing";
import { Size } from "../models/size";
describe('MovingTool', () => {
@ -47,8 +48,42 @@ describe('MovingTool', () => {
it('canvas should transformed', () => {
expect(svg.canvas.attr('transform')).toEqual('translate(100, 100) scale(1)');
});
it('context transformation should be updated', () => {
expect(context.transformation.x).toEqual(100);
expect(context.transformation.y).toEqual(100);
expect(context.transformation.k).toEqual(1);
});
});
describe('MovingTool can move canvas with ZeroZeroTransformationPoint', () => {
beforeEach(() => {
context.centerZeroZeroPoint = true;
context.size = new Size(1000, 1000);
svg.svg.node().dispatchEvent(
new MouseEvent('mousedown', {
clientX: 100, clientY: 100, relatedTarget: svg.svg.node(),
screenY: 1024, screenX: 1024, view: window
})
);
window.dispatchEvent(new MouseEvent('mousemove', {clientX: 200, clientY: 200}));
window.dispatchEvent(new MouseEvent('mouseup', {clientX: 200, clientY: 200, view: window}));
});
it('canvas should transformed', () => {
expect(svg.canvas.attr('transform')).toEqual('translate(600, 600) scale(1)');
});
it('context transformation should be updated', () => {
expect(context.transformation.x).toEqual(100);
expect(context.transformation.y).toEqual(100);
expect(context.transformation.k).toEqual(1);
});
});
describe('MovingTool can be deactivated', () => {
beforeEach(() => {
tool.deactivate();

View File

@ -1,8 +1,10 @@
import {SVGSelection} from "../models/types";
import {Context} from "../models/context";
import {D3ZoomEvent, zoom, ZoomBehavior} from "d3-zoom";
import { D3ZoomEvent, zoom, ZoomBehavior} from "d3-zoom";
import { event } from "d3-selection";
import { SVGSelection} from "../models/types";
import { Context} from "../models/context";
export class MovingTool {
private selection: SVGSelection;
private context: Context;
@ -32,9 +34,17 @@ export class MovingTool {
const canvas = self.selection.select<SVGGElement>("g.canvas");
const e: D3ZoomEvent<SVGSVGElement, any> = event;
canvas.attr(
'transform',
`translate(${self.context.getSize().width / 2 + e.transform.x}, ` +
`${self.context.getSize().height / 2 + e.transform.y}) scale(${e.transform.k})`);
'transform',
() => {
self.context.transformation.x = e.transform.x;
self.context.transformation.y = e.transform.y;
self.context.transformation.k = e.transform.k;
const xTrans = self.context.getZeroZeroTransformationPoint().x + self.context.transformation.x;
const yTrans = self.context.getZeroZeroTransformationPoint().y + self.context.transformation.y;
const kTrans = self.context.transformation.k;
return `translate(${xTrans}, ${yTrans}) scale(${kTrans})`;
});
};
this.zoom.on('zoom', onZoom);

View File

@ -113,4 +113,16 @@ describe('SelectionTool', () => {
expect(path_selection.attr('visibility')).toEqual('hidden');
});
});
describe('SelectionTool correctly transform points with context transformation', () => {
beforeEach(() => {
context.transformation.x = 100;
context.transformation.y = 100;
svg.svg.node().dispatchEvent(new MouseEvent('mousedown', {clientX: 100, clientY: 100}));
});
it('path should have d adjusted for transformation', () => {
expect(path_selection.attr('d')).toEqual('M-5,-14 l0,0 l0,0 l0,0z');
});
});
});

View File

@ -105,7 +105,10 @@ export class SelectionTool {
private transformation(point) {
const transformation_point = this.context.getZeroZeroTransformationPoint();
return [point[0] - transformation_point.x, point[1] - transformation_point.y];
return [
point[0] - transformation_point.x - this.context.transformation.x,
point[1] - transformation_point.y - this.context.transformation.y
];
}

View File

@ -27,8 +27,6 @@ export class GraphLayout implements Widget {
private movingTool: MovingTool;
private layersWidget: LayersWidget;
private centerZeroZeroPoint = true;
constructor() {
this.linksWidget = new LinksWidget();
this.nodesWidget = new NodesWidget();
@ -89,14 +87,19 @@ export class GraphLayout implements Widget {
.data([context]);
const canvasEnter = canvas.enter()
.append<SVGGElement>('g')
.attr('class', 'canvas');
.append<SVGGElement>('g')
.attr('class', 'canvas');
if (this.centerZeroZeroPoint) {
canvas.attr(
'transform',
(ctx: Context) => `translate(${ctx.getSize().width / 2}, ${ctx.getSize().height / 2})`);
}
canvas
.merge(canvasEnter)
.attr(
'transform',
(ctx: Context) => {
const xTrans = ctx.getZeroZeroTransformationPoint().x + ctx.transformation.x;
const yTrans = ctx.getZeroZeroTransformationPoint().y + ctx.transformation.y;
const kTrans = ctx.transformation.k;
return `translate(${xTrans}, ${yTrans}) scale(${kTrans})`;
});
const layersManager = new LayersManager();
layersManager.setNodes(this.nodes);