mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-01-19 03:06:31 +00:00
Drawings - draw as different shapes
This commit is contained in:
parent
0b47232f89
commit
6002ebacdf
@ -1,4 +1,5 @@
|
||||
import { SvgToDrawingConverter } from "./svg-to-drawing-converter";
|
||||
import { TextElement } from "../../shared/models/drawings/text-element";
|
||||
|
||||
|
||||
describe('SvgToDrawingHelper', () => {
|
||||
@ -16,7 +17,7 @@ describe('SvgToDrawingHelper', () => {
|
||||
expect(() => svgToDrawingConverter.convert("<svg></svg>")).toThrowError(Error);
|
||||
});
|
||||
|
||||
it('should raise Error on unknown parser', () => {
|
||||
it('should raise Error on unknown parser', () => {
|
||||
expect(() => svgToDrawingConverter.convert("<svg><unkown></unkown></svg>")).toThrowError(Error);
|
||||
});
|
||||
|
||||
@ -32,4 +33,14 @@ describe('SvgToDrawingHelper', () => {
|
||||
expect(drawing.width).toBe(78);
|
||||
expect(drawing.height).toBe(53);
|
||||
});
|
||||
|
||||
it('should parse element even when is text between', () => {
|
||||
const svg = '<svg height="53" width="78"> <text>Label</text> </svg>';
|
||||
const drawing: TextElement = svgToDrawingConverter.convert(svg);
|
||||
expect(drawing.text).toEqual('Label');
|
||||
});
|
||||
|
||||
it('should match supported elements', () => {
|
||||
expect(svgToDrawingConverter.supportedTags()).toEqual(['text', 'image', 'rect', 'line', 'ellipse']);
|
||||
});
|
||||
});
|
||||
|
@ -2,6 +2,10 @@ import { Injectable } from "@angular/core";
|
||||
import { DrawingElement } from "../../shared/models/drawings/drawing-element";
|
||||
import { SvgConverter } from "./svg-to-drawing-converter/svg-converter";
|
||||
import { TextConverter } from "./svg-to-drawing-converter/text-converter";
|
||||
import { ImageConverter } from "./svg-to-drawing-converter/image-converter";
|
||||
import { RectConverter } from "./svg-to-drawing-converter/rect-converter";
|
||||
import { LineConverter } from "./svg-to-drawing-converter/line-converter";
|
||||
import { EllipseConverter } from "./svg-to-drawing-converter/ellipse-converter";
|
||||
|
||||
|
||||
@Injectable()
|
||||
@ -12,10 +16,18 @@ export class SvgToDrawingConverter {
|
||||
constructor() {
|
||||
this.parser = new DOMParser();
|
||||
this.elementParsers = {
|
||||
'text': new TextConverter()
|
||||
'text': new TextConverter(),
|
||||
'image': new ImageConverter(),
|
||||
'rect': new RectConverter(),
|
||||
'line': new LineConverter(),
|
||||
'ellipse': new EllipseConverter()
|
||||
};
|
||||
}
|
||||
|
||||
supportedTags() {
|
||||
return Object.keys(this.elementParsers);
|
||||
}
|
||||
|
||||
convert(svg: string): DrawingElement {
|
||||
const svgDom = this.parser.parseFromString(svg, 'text/xml');
|
||||
const roots = svgDom.getElementsByTagName('svg');
|
||||
@ -24,17 +36,23 @@ export class SvgToDrawingConverter {
|
||||
}
|
||||
const svgRoot = roots[0];
|
||||
|
||||
const child = svgRoot.firstChild;
|
||||
if (!child) {
|
||||
throw new Error(`Cannot find first child in '${svg}`);
|
||||
let parser: SvgConverter = null;
|
||||
let child: any = null;
|
||||
|
||||
// find matching tag
|
||||
for (const i in svgRoot.children) {
|
||||
child = svgRoot.children[i];
|
||||
const name = child.nodeName;
|
||||
if (name in this.elementParsers) {
|
||||
parser = this.elementParsers[name];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const name = child.nodeName;
|
||||
if (!(name in this.elementParsers)) {
|
||||
throw new Error(`Cannot find parser for '${name}'`);
|
||||
if (parser === null) {
|
||||
throw new Error(`Cannot find parser for '${svg}'`);
|
||||
}
|
||||
|
||||
const parser = this.elementParsers[name];
|
||||
const drawing = parser.convert(child);
|
||||
|
||||
drawing.width = +svgRoot.getAttribute('width');
|
||||
|
@ -0,0 +1,33 @@
|
||||
import { EllipseConverter } from "./ellipse-converter";
|
||||
|
||||
|
||||
describe('EllipseConverter', () => {
|
||||
let ellipseConverter: EllipseConverter;
|
||||
|
||||
beforeEach(() => {
|
||||
ellipseConverter = new EllipseConverter();
|
||||
});
|
||||
|
||||
it('should parse attributes', () => {
|
||||
const node = document.createElement("ellipse");
|
||||
node.setAttribute("fill", "#ffffff");
|
||||
node.setAttribute("fill-opacity", "1.0");
|
||||
node.setAttribute("stroke", "#000000");
|
||||
node.setAttribute("stroke-width", "2");
|
||||
node.setAttribute("cx", "63");
|
||||
node.setAttribute("cy", "59");
|
||||
node.setAttribute("rx", "63");
|
||||
node.setAttribute("ry", "59");
|
||||
|
||||
const drawing = ellipseConverter.convert(node);
|
||||
expect(drawing.fill).toEqual("#ffffff");
|
||||
expect(drawing.fill_opacity).toEqual(1.0);
|
||||
expect(drawing.stroke).toEqual("#000000");
|
||||
expect(drawing.stroke_width).toEqual(2.0);
|
||||
expect(drawing.cx).toEqual(63);
|
||||
expect(drawing.cy).toEqual(59);
|
||||
expect(drawing.rx).toEqual(63);
|
||||
expect(drawing.ry).toEqual(59);
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,51 @@
|
||||
import { SvgConverter } from "./svg-converter";
|
||||
import { EllipseElement } from "../../../shared/models/drawings/ellipse-element";
|
||||
|
||||
|
||||
export class EllipseConverter implements SvgConverter {
|
||||
convert(node: Node): EllipseElement {
|
||||
const drawing = new EllipseElement();
|
||||
|
||||
const fill = node.attributes.getNamedItem("fill");
|
||||
if (fill) {
|
||||
drawing.fill = fill.value;
|
||||
}
|
||||
|
||||
const fill_opacity = node.attributes.getNamedItem("fill-opacity");
|
||||
if (fill) {
|
||||
drawing.fill_opacity = parseInt(fill_opacity.value, 10);
|
||||
}
|
||||
|
||||
const stroke = node.attributes.getNamedItem("stroke");
|
||||
if (stroke) {
|
||||
drawing.stroke = stroke.value;
|
||||
}
|
||||
|
||||
const stroke_width = node.attributes.getNamedItem("stroke-width");
|
||||
if (stroke) {
|
||||
drawing.stroke_width = parseInt(stroke_width.value, 10);
|
||||
}
|
||||
|
||||
const cx = node.attributes.getNamedItem('cx');
|
||||
if (cx) {
|
||||
drawing.cx = parseInt(cx.value, 10);
|
||||
}
|
||||
|
||||
const cy = node.attributes.getNamedItem('cy');
|
||||
if (cy) {
|
||||
drawing.cy = parseInt(cy.value, 10);
|
||||
}
|
||||
|
||||
const rx = node.attributes.getNamedItem('rx');
|
||||
if (rx) {
|
||||
drawing.rx = parseInt(rx.value, 10);
|
||||
}
|
||||
|
||||
const ry = node.attributes.getNamedItem('ry');
|
||||
if (ry) {
|
||||
drawing.ry = parseInt(ry.value, 10);
|
||||
}
|
||||
|
||||
return drawing;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import { ImageConverter } from "./image-converter";
|
||||
|
||||
|
||||
describe('ImageConverter', () => {
|
||||
let imageConverter: ImageConverter;
|
||||
|
||||
beforeEach(() => {
|
||||
imageConverter = new ImageConverter();
|
||||
});
|
||||
|
||||
it('should parse attributes', () => {
|
||||
const node = document.createElement("image");
|
||||
node.setAttribute("xlink:href", "data:image/png");
|
||||
node.setAttribute("width", "100px");
|
||||
node.setAttribute("height", "200px");
|
||||
|
||||
const drawing = imageConverter.convert(node);
|
||||
expect(drawing.data).toEqual("data:image/png");
|
||||
expect(drawing.width).toEqual(100);
|
||||
expect(drawing.height).toEqual(200);
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,26 @@
|
||||
import { SvgConverter } from "./svg-converter";
|
||||
import { ImageElement } from "../../../shared/models/drawings/image-element";
|
||||
|
||||
|
||||
export class ImageConverter implements SvgConverter {
|
||||
convert(node: Node): ImageElement {
|
||||
const drawing = new ImageElement();
|
||||
|
||||
const data = node.attributes.getNamedItem("xlink:href");
|
||||
if (data) {
|
||||
drawing.data = data.value;
|
||||
}
|
||||
|
||||
const width = node.attributes.getNamedItem('width');
|
||||
if (width) {
|
||||
drawing.width = parseInt(width.value, 10);
|
||||
}
|
||||
|
||||
const height = node.attributes.getNamedItem('height');
|
||||
if (height) {
|
||||
drawing.height = parseInt(height.value, 10);
|
||||
}
|
||||
|
||||
return drawing;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
import { LineConverter } from "./line-converter";
|
||||
|
||||
|
||||
describe('LineConverter', () => {
|
||||
let lineConverter: LineConverter;
|
||||
|
||||
beforeEach(() => {
|
||||
lineConverter = new LineConverter();
|
||||
});
|
||||
|
||||
it('should parse attributes', () => {
|
||||
const node = document.createElement("line");
|
||||
node.setAttribute("stroke", "#000000");
|
||||
node.setAttribute("stroke-width", "2");
|
||||
node.setAttribute("x1", "10.10");
|
||||
node.setAttribute("x2", "20");
|
||||
node.setAttribute("y1", "30");
|
||||
node.setAttribute("y2", "40");
|
||||
|
||||
const drawing = lineConverter.convert(node);
|
||||
expect(drawing.stroke).toEqual("#000000");
|
||||
expect(drawing.stroke_width).toEqual(2.0);
|
||||
expect(drawing.x1).toEqual(10);
|
||||
expect(drawing.x2).toEqual(20);
|
||||
expect(drawing.y1).toEqual(30);
|
||||
expect(drawing.y2).toEqual(40);
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,41 @@
|
||||
import { SvgConverter } from "./svg-converter";
|
||||
import { LineElement } from "../../../shared/models/drawings/line-element";
|
||||
|
||||
|
||||
export class LineConverter implements SvgConverter {
|
||||
convert(node: Node): LineElement {
|
||||
const drawing = new LineElement();
|
||||
|
||||
const stroke = node.attributes.getNamedItem("stroke");
|
||||
if (stroke) {
|
||||
drawing.stroke = stroke.value;
|
||||
}
|
||||
|
||||
const stroke_width = node.attributes.getNamedItem("stroke-width");
|
||||
if (stroke) {
|
||||
drawing.stroke_width = parseInt(stroke_width.value, 10);
|
||||
}
|
||||
|
||||
const x1 = node.attributes.getNamedItem('x1');
|
||||
if (x1) {
|
||||
drawing.x1 = parseInt(x1.value, 10);
|
||||
}
|
||||
|
||||
const x2 = node.attributes.getNamedItem('x2');
|
||||
if (x2) {
|
||||
drawing.x2 = parseInt(x2.value, 10);
|
||||
}
|
||||
|
||||
const y1 = node.attributes.getNamedItem('y1');
|
||||
if (y1) {
|
||||
drawing.y1 = parseInt(y1.value, 10);
|
||||
}
|
||||
|
||||
const y2 = node.attributes.getNamedItem('y2');
|
||||
if (y2) {
|
||||
drawing.y2 = parseInt(y2.value, 10);
|
||||
}
|
||||
|
||||
return drawing;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
import { RectConverter } from "./rect-converter";
|
||||
|
||||
|
||||
describe('RectConverter', () => {
|
||||
let rectConverter: RectConverter;
|
||||
|
||||
beforeEach(() => {
|
||||
rectConverter = new RectConverter();
|
||||
});
|
||||
|
||||
it('should parse attributes', () => {
|
||||
const node = document.createElement("rect");
|
||||
node.setAttribute("fill", "#ffffff");
|
||||
node.setAttribute("fill-opacity", "1.0");
|
||||
node.setAttribute("stroke", "#000000");
|
||||
node.setAttribute("stroke-width", "2");
|
||||
|
||||
node.setAttribute("width", "100px");
|
||||
node.setAttribute("height", "200px");
|
||||
|
||||
const drawing = rectConverter.convert(node);
|
||||
expect(drawing.fill).toEqual("#ffffff");
|
||||
expect(drawing.fill_opacity).toEqual(1.0);
|
||||
expect(drawing.stroke).toEqual("#000000");
|
||||
expect(drawing.stroke_width).toEqual(2.0);
|
||||
expect(drawing.width).toEqual(100);
|
||||
expect(drawing.height).toEqual(200);
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,41 @@
|
||||
import { SvgConverter } from "./svg-converter";
|
||||
import { RectElement } from "../../../shared/models/drawings/rect-element";
|
||||
|
||||
|
||||
export class RectConverter implements SvgConverter {
|
||||
convert(node: Node): RectElement {
|
||||
const drawing = new RectElement();
|
||||
|
||||
const fill = node.attributes.getNamedItem("fill");
|
||||
if (fill) {
|
||||
drawing.fill = fill.value;
|
||||
}
|
||||
|
||||
const fill_opacity = node.attributes.getNamedItem("fill-opacity");
|
||||
if (fill) {
|
||||
drawing.fill_opacity = parseInt(fill_opacity.value, 10);
|
||||
}
|
||||
|
||||
const stroke = node.attributes.getNamedItem("stroke");
|
||||
if (stroke) {
|
||||
drawing.stroke = stroke.value;
|
||||
}
|
||||
|
||||
const stroke_width = node.attributes.getNamedItem("stroke-width");
|
||||
if (stroke) {
|
||||
drawing.stroke_width = parseInt(stroke_width.value, 10);
|
||||
}
|
||||
|
||||
const width = node.attributes.getNamedItem('width');
|
||||
if (width) {
|
||||
drawing.width = parseInt(width.value, 10);
|
||||
}
|
||||
|
||||
const height = node.attributes.getNamedItem('height');
|
||||
if (height) {
|
||||
drawing.height = parseInt(height.value, 10);
|
||||
}
|
||||
|
||||
return drawing;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { TextConverter } from "./text-converter";
|
||||
|
||||
|
||||
describe('SvgToDrawingHelper', () => {
|
||||
describe('TextConverter', () => {
|
||||
let textConverter: TextConverter;
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -4,6 +4,10 @@ import {SVGSelection} from "../models/types";
|
||||
import {Layer} from "../models/layer";
|
||||
import { TextDrawingWidget } from "./drawings/text-drawing";
|
||||
import { SvgToDrawingConverter } from "../../map/helpers/svg-to-drawing-converter";
|
||||
import { ImageDrawingWidget } from "./drawings/image-drawing";
|
||||
import { RectDrawingWidget } from "./drawings/rect-drawing";
|
||||
import { LineDrawingWidget } from "./drawings/line-drawing";
|
||||
import { EllipseDrawingWidget } from "./drawings/ellipse-drawing";
|
||||
|
||||
|
||||
export class DrawingsWidget implements Widget {
|
||||
@ -73,6 +77,18 @@ export class DrawingsWidget implements Widget {
|
||||
const text_drawing = new TextDrawingWidget();
|
||||
text_drawing.draw(drawing_merge);
|
||||
|
||||
const image_drawing = new ImageDrawingWidget();
|
||||
image_drawing.draw(drawing_merge);
|
||||
|
||||
const rect_drawing = new RectDrawingWidget();
|
||||
rect_drawing.draw(drawing_merge);
|
||||
|
||||
const line_drawing = new LineDrawingWidget();
|
||||
line_drawing.draw(drawing_merge);
|
||||
|
||||
const ellipse_drawing = new EllipseDrawingWidget();
|
||||
ellipse_drawing.draw(drawing_merge);
|
||||
|
||||
drawing
|
||||
.exit()
|
||||
.remove();
|
||||
|
@ -0,0 +1,53 @@
|
||||
import { TestSVGCanvas } from "../../../testing";
|
||||
import { Drawing } from "../../models/drawing";
|
||||
import { EllipseDrawingWidget } from "./ellipse-drawing";
|
||||
import { EllipseElement } from "../../models/drawings/ellipse-element";
|
||||
|
||||
|
||||
describe('EllipseDrawingWidget', () => {
|
||||
let svg: TestSVGCanvas;
|
||||
let widget: EllipseDrawingWidget;
|
||||
let drawing: Drawing;
|
||||
|
||||
|
||||
beforeEach(() => {
|
||||
svg = new TestSVGCanvas();
|
||||
drawing = new Drawing();
|
||||
widget = new EllipseDrawingWidget();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
svg.destroy();
|
||||
});
|
||||
|
||||
it('should draw ellipse drawing', () => {
|
||||
const ellipse = new EllipseElement();
|
||||
ellipse.fill = "#FFFFFFF";
|
||||
ellipse.fill_opacity = 2.0;
|
||||
ellipse.stroke = "#000000";
|
||||
ellipse.stroke_width = 2.0;
|
||||
ellipse.cx = 10;
|
||||
ellipse.cy = 20;
|
||||
ellipse.rx = 30;
|
||||
ellipse.ry = 40;
|
||||
drawing.element = ellipse;
|
||||
|
||||
const drawings = svg.canvas.selectAll<SVGGElement, Drawing>('g.drawing').data([drawing]);
|
||||
const drawings_enter = drawings.enter().append<SVGGElement>('g').classed('drawing', true);
|
||||
const drawings_merge = drawings.merge(drawings_enter);
|
||||
|
||||
widget.draw(drawings_merge);
|
||||
|
||||
const drew = drawings_merge.selectAll<SVGEllipseElement, EllipseElement>('ellipse.ellipse_element');
|
||||
expect(drew.size()).toEqual(1);
|
||||
const ellipse_element = drew.nodes()[0];
|
||||
expect(ellipse_element.getAttribute('fill')).toEqual('#FFFFFFF');
|
||||
expect(ellipse_element.getAttribute('fill-opacity')).toEqual('2');
|
||||
expect(ellipse_element.getAttribute('stroke')).toEqual('#000000');
|
||||
expect(ellipse_element.getAttribute('stroke-width')).toEqual('2');
|
||||
expect(ellipse_element.getAttribute('cx')).toEqual('10');
|
||||
expect(ellipse_element.getAttribute('cy')).toEqual('20');
|
||||
expect(ellipse_element.getAttribute('rx')).toEqual('30');
|
||||
expect(ellipse_element.getAttribute('ry')).toEqual('40');
|
||||
});
|
||||
});
|
@ -0,0 +1,36 @@
|
||||
import { SVGSelection } from "../../models/types";
|
||||
import { Drawing } from "../../models/drawing";
|
||||
import { EllipseElement } from "../../models/drawings/ellipse-element";
|
||||
|
||||
|
||||
export class EllipseDrawingWidget {
|
||||
public draw(view: SVGSelection) {
|
||||
const drawing = view
|
||||
.selectAll<SVGEllipseElement, EllipseElement>('ellipse.ellipse_element')
|
||||
.data((d: Drawing) => {
|
||||
return (d.element && d.element instanceof EllipseElement) ? [d.element] : [];
|
||||
});
|
||||
|
||||
const drawing_enter = drawing
|
||||
.enter()
|
||||
.append<SVGEllipseElement>('ellipse')
|
||||
.attr('class', 'ellipse_element noselect');
|
||||
|
||||
const merge = drawing.merge(drawing_enter);
|
||||
|
||||
merge
|
||||
.attr('fill', (ellipse) => ellipse.fill)
|
||||
.attr('fill-opacity', (ellipse) => ellipse.fill_opacity)
|
||||
.attr('stroke', (ellipse) => ellipse.stroke)
|
||||
.attr('stroke-width', (ellipse) => ellipse.stroke_width)
|
||||
.attr('cx', (ellipse) => ellipse.cx)
|
||||
.attr('cy', (ellipse) => ellipse.cy)
|
||||
.attr('rx', (ellipse) => ellipse.rx)
|
||||
.attr('ry', (ellipse) => ellipse.ry);
|
||||
|
||||
drawing
|
||||
.exit()
|
||||
.remove();
|
||||
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ describe('ImageDrawingWidget', () => {
|
||||
const image = new ImageElement();
|
||||
image.width = 100;
|
||||
image.height = 200;
|
||||
image.data = "DATA";
|
||||
image.data = "data:image/svg+xml;base64,DATA";
|
||||
drawing.element = image;
|
||||
|
||||
const drawings = svg.canvas.selectAll<SVGGElement, Drawing>('g.drawing').data([drawing]);
|
||||
@ -38,6 +38,6 @@ describe('ImageDrawingWidget', () => {
|
||||
const image_element = drew.nodes()[0];
|
||||
expect(image_element.getAttribute('width')).toEqual('100');
|
||||
expect(image_element.getAttribute('height')).toEqual('200');
|
||||
expect(image_element.getAttribute('href')).toEqual('data:image/svg+xml;base64,REFUQQ==');
|
||||
expect(image_element.getAttribute('href')).toEqual('data:image/svg+xml;base64,DATA');
|
||||
});
|
||||
});
|
||||
|
@ -19,17 +19,10 @@ export class ImageDrawingWidget {
|
||||
const merge = drawing.merge(drawing_enter);
|
||||
|
||||
merge
|
||||
.attr('xlink:href', (image: ImageElement) => {
|
||||
let svg = image.data;
|
||||
if (svg.indexOf("xmlns") < 0) {
|
||||
svg = svg.replace('svg', 'svg xmlns="http://www.w3.org/2000/svg"');
|
||||
}
|
||||
return 'data:image/svg+xml;base64,' + btoa(svg);
|
||||
})
|
||||
.attr('xlink:href', (image: ImageElement) => image.data)
|
||||
.attr('width', (image) => image.width)
|
||||
.attr('height', (image) => image.height);
|
||||
|
||||
|
||||
drawing
|
||||
.exit()
|
||||
.remove();
|
||||
|
@ -0,0 +1,49 @@
|
||||
import { TestSVGCanvas } from "../../../testing";
|
||||
import { Drawing } from "../../models/drawing";
|
||||
import { LineDrawingWidget } from "./line-drawing";
|
||||
import { LineElement } from "../../models/drawings/line-element";
|
||||
|
||||
|
||||
describe('LineDrawingWidget', () => {
|
||||
let svg: TestSVGCanvas;
|
||||
let widget: LineDrawingWidget;
|
||||
let drawing: Drawing;
|
||||
|
||||
|
||||
beforeEach(() => {
|
||||
svg = new TestSVGCanvas();
|
||||
drawing = new Drawing();
|
||||
widget = new LineDrawingWidget();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
svg.destroy();
|
||||
});
|
||||
|
||||
it('should draw line drawing', () => {
|
||||
const line = new LineElement();
|
||||
line.stroke = "#000000";
|
||||
line.stroke_width = 2.0;
|
||||
line.x1 = 10;
|
||||
line.x2 = 20;
|
||||
line.y1 = 30;
|
||||
line.y2 = 40;
|
||||
drawing.element = line;
|
||||
|
||||
const drawings = svg.canvas.selectAll<SVGGElement, Drawing>('g.drawing').data([drawing]);
|
||||
const drawings_enter = drawings.enter().append<SVGGElement>('g').classed('drawing', true);
|
||||
const drawings_merge = drawings.merge(drawings_enter);
|
||||
|
||||
widget.draw(drawings_merge);
|
||||
|
||||
const drew = drawings_merge.selectAll<SVGLineElement, LineElement>('line.line_element');
|
||||
expect(drew.size()).toEqual(1);
|
||||
const line_element = drew.nodes()[0];
|
||||
expect(line_element.getAttribute('stroke')).toEqual('#000000');
|
||||
expect(line_element.getAttribute('stroke-width')).toEqual('2');
|
||||
expect(line_element.getAttribute('x1')).toEqual('10');
|
||||
expect(line_element.getAttribute('x2')).toEqual('20');
|
||||
expect(line_element.getAttribute('y1')).toEqual('30');
|
||||
expect(line_element.getAttribute('y2')).toEqual('40');
|
||||
});
|
||||
});
|
34
src/app/cartography/shared/widgets/drawings/line-drawing.ts
Normal file
34
src/app/cartography/shared/widgets/drawings/line-drawing.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { SVGSelection } from "../../models/types";
|
||||
import { Drawing } from "../../models/drawing";
|
||||
import { LineElement } from "../../models/drawings/line-element";
|
||||
|
||||
|
||||
export class LineDrawingWidget {
|
||||
public draw(view: SVGSelection) {
|
||||
const drawing = view
|
||||
.selectAll<SVGLineElement, LineElement>('line.line_element')
|
||||
.data((d: Drawing) => {
|
||||
return (d.element && d.element instanceof LineElement) ? [d.element] : [];
|
||||
});
|
||||
|
||||
const drawing_enter = drawing
|
||||
.enter()
|
||||
.append<SVGLineElement>('line')
|
||||
.attr('class', 'line_element noselect');
|
||||
|
||||
const merge = drawing.merge(drawing_enter);
|
||||
|
||||
merge
|
||||
.attr('stroke', (line) => line.stroke)
|
||||
.attr('stroke-width', (line) => line.stroke_width)
|
||||
.attr('x1', (line) => line.x1)
|
||||
.attr('x2', (line) => line.x2)
|
||||
.attr('y1', (line) => line.y1)
|
||||
.attr('y2', (line) => line.y2);
|
||||
|
||||
drawing
|
||||
.exit()
|
||||
.remove();
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
import { TestSVGCanvas } from "../../../testing";
|
||||
import { Drawing } from "../../models/drawing";
|
||||
import { RectDrawingWidget } from "./rect-drawing";
|
||||
import { RectElement } from "../../models/drawings/rect-element";
|
||||
|
||||
|
||||
describe('RectDrawingWidget', () => {
|
||||
let svg: TestSVGCanvas;
|
||||
let widget: RectDrawingWidget;
|
||||
let drawing: Drawing;
|
||||
|
||||
|
||||
beforeEach(() => {
|
||||
svg = new TestSVGCanvas();
|
||||
drawing = new Drawing();
|
||||
widget = new RectDrawingWidget();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
svg.destroy();
|
||||
});
|
||||
|
||||
it('should draw rect drawing', () => {
|
||||
const rect = new RectElement();
|
||||
rect.fill = "#FFFFFF";
|
||||
rect.fill_opacity = 1.0;
|
||||
rect.stroke = "#000000";
|
||||
rect.stroke_width = 2.0;
|
||||
rect.width = 100;
|
||||
rect.height = 200;
|
||||
drawing.element = rect;
|
||||
|
||||
const drawings = svg.canvas.selectAll<SVGGElement, Drawing>('g.drawing').data([drawing]);
|
||||
const drawings_enter = drawings.enter().append<SVGGElement>('g').classed('drawing', true);
|
||||
const drawings_merge = drawings.merge(drawings_enter);
|
||||
|
||||
widget.draw(drawings_merge);
|
||||
|
||||
const drew = drawings_merge.selectAll<SVGRectElement, RectElement>('rect.rect_element');
|
||||
expect(drew.size()).toEqual(1);
|
||||
const rect_element = drew.nodes()[0];
|
||||
expect(rect_element.getAttribute('fill')).toEqual('#FFFFFF');
|
||||
expect(rect_element.getAttribute('fill-opacity')).toEqual('1');
|
||||
expect(rect_element.getAttribute('stroke')).toEqual('#000000');
|
||||
expect(rect_element.getAttribute('stroke-width')).toEqual('2');
|
||||
expect(rect_element.getAttribute('width')).toEqual('100');
|
||||
expect(rect_element.getAttribute('height')).toEqual('200');
|
||||
});
|
||||
});
|
34
src/app/cartography/shared/widgets/drawings/rect-drawing.ts
Normal file
34
src/app/cartography/shared/widgets/drawings/rect-drawing.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { SVGSelection } from "../../models/types";
|
||||
import { Drawing } from "../../models/drawing";
|
||||
import { RectElement } from "../../models/drawings/rect-element";
|
||||
|
||||
|
||||
export class RectDrawingWidget {
|
||||
public draw(view: SVGSelection) {
|
||||
const drawing = view
|
||||
.selectAll<SVGRectElement, RectElement>('rect.rect_element')
|
||||
.data((d: Drawing) => {
|
||||
return (d.element && d.element instanceof RectElement) ? [d.element] : [];
|
||||
});
|
||||
|
||||
const drawing_enter = drawing
|
||||
.enter()
|
||||
.append<SVGRectElement>('rect')
|
||||
.attr('class', 'rect_element noselect');
|
||||
|
||||
const merge = drawing.merge(drawing_enter);
|
||||
|
||||
merge
|
||||
.attr('fill', (rect) => rect.fill)
|
||||
.attr('fill-opacity', (rect) => rect.fill_opacity)
|
||||
.attr('stroke', (rect) => rect.stroke)
|
||||
.attr('stroke-width', (rect) => rect.stroke_width)
|
||||
.attr('width', (rect) => rect.width)
|
||||
.attr('height', (rect) => rect.height);
|
||||
|
||||
drawing
|
||||
.exit()
|
||||
.remove();
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user