diff --git a/src/app/cartography/map/map.component.ts b/src/app/cartography/map/map.component.ts index 175f3b3e..ca00d3c5 100644 --- a/src/app/cartography/map/map.component.ts +++ b/src/app/cartography/map/map.component.ts @@ -7,6 +7,7 @@ import { Link } from "../shared/models/link.model"; import { GraphLayout } from "../shared/widgets/graph.widget"; import { Context } from "../../map/models/context"; import { Size } from "../shared/models/size.model"; +import { Drawing } from "../shared/models/drawing.model"; @Component({ @@ -17,6 +18,7 @@ import { Size } from "../shared/models/size.model"; export class MapComponent implements OnInit, OnChanges, OnDestroy { @Input() nodes: Node[] = []; @Input() links: Link[] = []; + @Input() drawings: Drawing[] = []; @Input() width = 1500; @Input() height = 600; @Input() phylloRadius = 7; @@ -43,6 +45,7 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy { (changes['height'] && !changes['height'].isFirstChange()) || (changes['phylloRadius'] && !changes['phylloRadius'].isFirstChange()) || (changes['pointRadius'] && !changes['pointRadius'].isFirstChange()) || + (changes['drawings'] && !changes['drawings'].isFirstChange()) || (changes['nodes'] && !changes['nodes'].isFirstChange()) || (changes['links'] && !changes['links'].isFirstChange()) ) { @@ -115,6 +118,7 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy { this.graphLayout.setNodes(this.nodes); this.graphLayout.setLinks(this.links); + this.graphLayout.setDrawings(this.drawings); this.redraw(); } diff --git a/src/app/cartography/shared/models/drawing.model.ts b/src/app/cartography/shared/models/drawing.model.ts new file mode 100644 index 00000000..337bc0a6 --- /dev/null +++ b/src/app/cartography/shared/models/drawing.model.ts @@ -0,0 +1,9 @@ +export class Drawing { + drawing_id: string; + project_id: string; + rotation: number; + svg: string; + x: number; + y: number; + z: number; +} diff --git a/src/app/cartography/shared/widgets/drawings.widget.ts b/src/app/cartography/shared/widgets/drawings.widget.ts new file mode 100644 index 00000000..621b0c8c --- /dev/null +++ b/src/app/cartography/shared/widgets/drawings.widget.ts @@ -0,0 +1,60 @@ +import {Widget} from "./widget"; +import {Drawing} from "../models/drawing.model"; +import {SVGSelection} from "../../../map/models/types"; + + +export class DrawingsWidget implements Widget { + constructor() {} + + public draw(view: SVGSelection, drawings: Drawing[]) { + const drawing = view.selectAll('g.drawing') + .data(drawings); + + const drawing_enter = drawing.enter() + .append('g') + .attr('class', 'drawing'); + + const parser = new DOMParser(); + + const drawing_image = drawing_enter.append('image') + .attr('xlink:href', (d: Drawing) => { + let svg = d.svg; + 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('width', (d: Drawing) => { + const svg_dom = parser.parseFromString(d.svg, 'text/xml'); + const roots = svg_dom.getElementsByTagName('svg'); + if (roots.length > 0) { + if (roots[0].hasAttribute('width')) { + return roots[0].getAttribute('width'); + } + } + return 0; + }) + .attr('height', (d: Drawing) => { + const svg_dom = parser.parseFromString(d.svg, 'text/xml'); + const roots = svg_dom.getElementsByTagName('svg'); + if (roots.length > 0) { + if (roots[0].hasAttribute('height')) { + return roots[0].getAttribute('height'); + } + } + return 0; + }); + + const drawing_merge = drawing.merge(drawing_enter) + .attr('transform', (d: Drawing) => { + return `translate(${d.x},${d.y})`; + }); + + drawing.exit().remove(); + } + + private appendSVG(svg: string) { + + } +} diff --git a/src/app/cartography/shared/widgets/graph.widget.ts b/src/app/cartography/shared/widgets/graph.widget.ts index be06eb7e..d4c59a19 100644 --- a/src/app/cartography/shared/widgets/graph.widget.ts +++ b/src/app/cartography/shared/widgets/graph.widget.ts @@ -7,14 +7,18 @@ import { SVGSelection } from "../../../map/models/types"; import { LinksWidget } from "./links.widget"; import { D3ZoomEvent, zoom } from "d3-zoom"; import { event } from "d3-selection"; +import {Drawing} from "../models/drawing.model"; +import {DrawingsWidget} from "./drawings.widget"; export class GraphLayout implements Widget { private nodes: Node[] = []; private links: Link[] = []; + private drawings: Drawing[] = []; private nodesWidget = new NodesWidget(); private linksWidget = new LinksWidget(); + private drawingsWidget = new DrawingsWidget(); private centerZeroZeroPoint = true; @@ -26,42 +30,46 @@ export class GraphLayout implements Widget { this.links = links; } + public setDrawings(drawings: Drawing[]) { + this.drawings = drawings; + } draw(view: SVGSelection, context: Context) { const self = this; - const drawing = view - .selectAll('g.drawing') + const canvas = view + .selectAll('g.canvas') .data([context]); - const drawingEnter = drawing.enter() + const canvasEnter = canvas.enter() .append('g') - .attr('class', 'drawing'); + .attr('class', 'canvas'); if (this.centerZeroZeroPoint) { - drawing.attr( + canvas.attr( 'transform', (ctx: Context) => `translate(${ctx.getSize().width / 2}, ${ctx.getSize().height / 2})`); } - const links = drawingEnter.append('g') - .attr('class', 'links'); + // const links = canvasEnter.append('g') + // .attr('class', 'links'); + // + // const nodes = canvasEnter.append('g') + // .attr('class', 'nodes'); - const nodes = drawingEnter.append('g') - .attr('class', 'nodes'); - - this.linksWidget.draw(drawing, this.links); - this.nodesWidget.draw(drawing, this.nodes); + this.linksWidget.draw(canvas, this.links); + this.nodesWidget.draw(canvas, this.nodes); + this.drawingsWidget.draw(canvas, this.drawings) const onZoom = function(this: SVGSVGElement) { const e: D3ZoomEvent = event; if (self.centerZeroZeroPoint) { - drawing.attr( + canvas.attr( 'transform', `translate(${context.getSize().width / 2 + e.transform.x}, ` + `${context.getSize().height / 2 + e.transform.y}) scale(${e.transform.k})`); } else { - drawing.attr('transform', e.transform.toString()); + canvas.attr('transform', e.transform.toString()); } }; diff --git a/src/app/map/map.component.html b/src/app/map/map.component.html index c56fc706..5fe8c1c8 100644 --- a/src/app/map/map.component.html +++ b/src/app/map/map.component.html @@ -1 +1 @@ - + diff --git a/src/app/project-map/project-map.component.html b/src/app/project-map/project-map.component.html index c095efa5..ed0e5ce4 100644 --- a/src/app/project-map/project-map.component.html +++ b/src/app/project-map/project-map.component.html @@ -1,5 +1,5 @@
- +
diff --git a/src/app/project-map/project-map.component.ts b/src/app/project-map/project-map.component.ts index fac9c43d..04cd01c4 100644 --- a/src/app/project-map/project-map.component.ts +++ b/src/app/project-map/project-map.component.ts @@ -25,6 +25,7 @@ import { Snapshot } from "../shared/models/snapshot"; import { ProgressDialogService } from "../shared/progress-dialog/progress-dialog.service"; import { ProgressDialogComponent } from "../shared/progress-dialog/progress-dialog.component"; import { ToastyService } from "ng2-toasty"; +import {Drawing} from "../cartography/shared/models/drawing.model"; @Component({ @@ -36,6 +37,7 @@ import { ToastyService } from "ng2-toasty"; export class ProjectMapComponent implements OnInit { public nodes: Node[] = []; public links: Link[] = []; + public drawings: Drawing[] = []; project: Project; server: Server; @@ -86,6 +88,10 @@ export class ProjectMapComponent implements OnInit { this.symbolService .load(this.server) .flatMap(() => { + return this.projectService.drawings(this.server, project.project_id); + }) + .flatMap((drawings: Drawing[]) => { + this.drawings = drawings; return this.projectService.links(this.server, project.project_id); }) .flatMap((links: Link[]) => { diff --git a/src/app/shared/services/project.service.ts b/src/app/shared/services/project.service.ts index d896610f..985c3bfc 100644 --- a/src/app/shared/services/project.service.ts +++ b/src/app/shared/services/project.service.ts @@ -7,6 +7,7 @@ import 'rxjs/add/operator/map'; import { Link } from "../../cartography/shared/models/link.model"; import { Server } from "../models/server"; import { HttpServer } from "./http-server.service"; +import {Drawing} from "../../cartography/shared/models/drawing.model"; @Injectable() export class ProjectService { @@ -43,6 +44,12 @@ export class ProjectService { .map(response => response.json() as Link[]); } + drawings(server: Server, project_id: string): Observable { + return this.httpServer + .get(server, `/projects/${project_id}/drawings`) + .map(response => response.json() as Drawing[]); + } + delete(server: Server, project_id: string): Observable { return this.httpServer .delete(server, `/projects/${project_id}`);