From 3d25633a38427dc447e8858e9c50f46212b73705 Mon Sep 17 00:00:00 2001 From: ziajka Date: Mon, 19 Mar 2018 10:30:29 +0100 Subject: [PATCH] Get selected nodes --- .../shared/tools/selection-tool.spec.ts | 23 +++++++++ .../shared/tools/selection-tool.ts | 50 +++++++++++++------ src/app/project-map/project-map.component.css | 4 ++ 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/app/cartography/shared/tools/selection-tool.spec.ts b/src/app/cartography/shared/tools/selection-tool.spec.ts index b606dea3..ea505c72 100644 --- a/src/app/cartography/shared/tools/selection-tool.spec.ts +++ b/src/app/cartography/shared/tools/selection-tool.spec.ts @@ -5,16 +5,30 @@ import {SVGSelection} from "../../../map/models/types"; import {Node} from "../models/node.model"; +class OnSelectedListenerMock { + public constructor(public nodes: Node[] = []) {} + + public listen(nodes: Node[]) { + console.log(this); + this.nodes = nodes; + } +} + describe('SelectionTool', () => { let tool: SelectionTool; let svg: SVGSelection; let context: Context; let selection_line_tool: SVGSelection; let path_selection: SVGSelection; + let selected_nodes: Node[]; beforeEach(() => { tool = new SelectionTool(); + tool.selectedSubject.subscribe((nodes: Node[]) => { + selected_nodes = nodes; + }); + svg = select('body') .append('svg') .attr('width', 1000) @@ -95,14 +109,23 @@ describe('SelectionTool', () => { expect(svg.select('.selected').datum().name).toEqual("Node 1"); }); + it('selectedSubject should update nodes', () => { + expect(selected_nodes.length).toEqual(1); + }); + describe('SelectionTool can deselect after click outside', () => { beforeEach(() => { svg.node().dispatchEvent(new MouseEvent('mousedown', {clientX: 300, clientY: 300})); + window.dispatchEvent(new MouseEvent('mouseup', {clientX: 300, clientY: 300})); }); it('should have no selection', () => { expect(svg.selectAll('.selected').size()).toEqual(0); }); + + it('selectedSubject should clear nodes', () => { + expect(selected_nodes.length).toEqual(0); + }); }); }); diff --git a/src/app/cartography/shared/tools/selection-tool.ts b/src/app/cartography/shared/tools/selection-tool.ts index b898ac9e..d959f086 100644 --- a/src/app/cartography/shared/tools/selection-tool.ts +++ b/src/app/cartography/shared/tools/selection-tool.ts @@ -2,12 +2,20 @@ import {SVGSelection} from "../../../map/models/types"; import {mouse, select} from "d3-selection"; import {Context} from "../../../map/models/context"; import {Node} from "../models/node.model"; +import {Subject} from "rxjs/Subject"; export class SelectionTool { + static readonly SELECTABLE_CLASS = '.selectable'; + private selection: SVGSelection; private path; private context: Context; + public selectedSubject: Subject; + + public constructor() { + this.selectedSubject = new Subject(); + } public connect(selection: SVGSelection, context: Context) { this.selection = selection; @@ -31,26 +39,17 @@ export class SelectionTool { self.startSelection(start); // clear selection - self.selection.selectAll('.selectable').classed("selected", false); + self.selection + .selectAll(SelectionTool.SELECTABLE_CLASS) + .classed("selected", false); subject .on("mousemove.selection", function() { const end = transformation(mouse(parent)); self.moveSelection(start, end); - - const x = Math.min(start[0], end[0]); - const y = Math.min(start[1], end[1]); - const width = Math.abs(start[0] - end[0]); - const height = Math.abs(start[1] - end[1]); - - self.selection - .selectAll('.selectable') - .classed('selected', (node: Node, i) => { - return (x <= node.x && node.x < (x + width) && y <= node.y && node.y < (y + height)); - }); - }).on("mouseup.selection", function() { - self.endSelection(start, transformation(mouse(parent))); + const end = transformation(mouse(parent)); + self.endSelection(start, end); subject .on("mousemove.selection", null) .on("mouseup.selection", null); @@ -85,10 +84,33 @@ export class SelectionTool { private moveSelection(start, move) { this.path.attr("d", this.rect(start[0], start[1], move[0] - start[0], move[1] - start[1])); + this.getSelectedNodes(start, move); } private endSelection(start, end) { this.path.attr("visibility", "hidden"); + const selected_nodes = this.getSelectedNodes(start, end); + this.selectedSubject.next(selected_nodes); + } + + private getSelectedNodes(start, end): Node[] { + const x = Math.min(start[0], end[0]); + const y = Math.min(start[1], end[1]); + const width = Math.abs(start[0] - end[0]); + const height = Math.abs(start[1] - end[1]); + const nodes: Node[] = []; + + this.selection + .selectAll(SelectionTool.SELECTABLE_CLASS) + .classed('selected', (node: Node) => { + const in_rect = (x <= node.x && node.x < (x + width) && y <= node.y && node.y < (y + height)); + if (in_rect) { + nodes.push(node); + } + return in_rect; + }); + + return nodes; } private rect(x: number, y: number, w: number, h: number) { diff --git a/src/app/project-map/project-map.component.css b/src/app/project-map/project-map.component.css index 5e262453..e0454295 100644 --- a/src/app/project-map/project-map.component.css +++ b/src/app/project-map/project-map.component.css @@ -47,6 +47,10 @@ svg image:hover, svg image.chosen, .selectable.selected { filter: grayscale(100%); } +link.selectable.selected { + color: darkred; +} + .selection-line-tool .selection { fill: #7ccbe1; stroke: #66aec2 ;