Get selected nodes

This commit is contained in:
ziajka 2018-03-19 10:30:29 +01:00
parent bfe6613871
commit 3d25633a38
3 changed files with 63 additions and 14 deletions

View File

@ -5,16 +5,30 @@ import {SVGSelection} from "../../../map/models/types";
import {Node} from "../models/node.model"; 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', () => { describe('SelectionTool', () => {
let tool: SelectionTool; let tool: SelectionTool;
let svg: SVGSelection; let svg: SVGSelection;
let context: Context; let context: Context;
let selection_line_tool: SVGSelection; let selection_line_tool: SVGSelection;
let path_selection: SVGSelection; let path_selection: SVGSelection;
let selected_nodes: Node[];
beforeEach(() => { beforeEach(() => {
tool = new SelectionTool(); tool = new SelectionTool();
tool.selectedSubject.subscribe((nodes: Node[]) => {
selected_nodes = nodes;
});
svg = select('body') svg = select('body')
.append<SVGSVGElement>('svg') .append<SVGSVGElement>('svg')
.attr('width', 1000) .attr('width', 1000)
@ -95,14 +109,23 @@ describe('SelectionTool', () => {
expect(svg.select('.selected').datum().name).toEqual("Node 1"); 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', () => { describe('SelectionTool can deselect after click outside', () => {
beforeEach(() => { beforeEach(() => {
svg.node().dispatchEvent(new MouseEvent('mousedown', {clientX: 300, clientY: 300})); svg.node().dispatchEvent(new MouseEvent('mousedown', {clientX: 300, clientY: 300}));
window.dispatchEvent(new MouseEvent('mouseup', {clientX: 300, clientY: 300}));
}); });
it('should have no selection', () => { it('should have no selection', () => {
expect(svg.selectAll('.selected').size()).toEqual(0); expect(svg.selectAll('.selected').size()).toEqual(0);
}); });
it('selectedSubject should clear nodes', () => {
expect(selected_nodes.length).toEqual(0);
});
}); });
}); });

View File

@ -2,12 +2,20 @@ import {SVGSelection} from "../../../map/models/types";
import {mouse, select} from "d3-selection"; import {mouse, select} from "d3-selection";
import {Context} from "../../../map/models/context"; import {Context} from "../../../map/models/context";
import {Node} from "../models/node.model"; import {Node} from "../models/node.model";
import {Subject} from "rxjs/Subject";
export class SelectionTool { export class SelectionTool {
static readonly SELECTABLE_CLASS = '.selectable';
private selection: SVGSelection; private selection: SVGSelection;
private path; private path;
private context: Context; private context: Context;
public selectedSubject: Subject<Node[]>;
public constructor() {
this.selectedSubject = new Subject<Node[]>();
}
public connect(selection: SVGSelection, context: Context) { public connect(selection: SVGSelection, context: Context) {
this.selection = selection; this.selection = selection;
@ -31,26 +39,17 @@ export class SelectionTool {
self.startSelection(start); self.startSelection(start);
// clear selection // clear selection
self.selection.selectAll('.selectable').classed("selected", false); self.selection
.selectAll(SelectionTool.SELECTABLE_CLASS)
.classed("selected", false);
subject subject
.on("mousemove.selection", function() { .on("mousemove.selection", function() {
const end = transformation(mouse(parent)); const end = transformation(mouse(parent));
self.moveSelection(start, end); 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() { }).on("mouseup.selection", function() {
self.endSelection(start, transformation(mouse(parent))); const end = transformation(mouse(parent));
self.endSelection(start, end);
subject subject
.on("mousemove.selection", null) .on("mousemove.selection", null)
.on("mouseup.selection", null); .on("mouseup.selection", null);
@ -85,10 +84,33 @@ export class SelectionTool {
private moveSelection(start, move) { private moveSelection(start, move) {
this.path.attr("d", this.rect(start[0], start[1], move[0] - start[0], move[1] - start[1])); 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) { private endSelection(start, end) {
this.path.attr("visibility", "hidden"); 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) { private rect(x: number, y: number, w: number, h: number) {

View File

@ -47,6 +47,10 @@ svg image:hover, svg image.chosen, .selectable.selected {
filter: grayscale(100%); filter: grayscale(100%);
} }
link.selectable.selected {
color: darkred;
}
.selection-line-tool .selection { .selection-line-tool .selection {
fill: #7ccbe1; fill: #7ccbe1;
stroke: #66aec2 ; stroke: #66aec2 ;