Drawings, ref. #10

This commit is contained in:
ziajka 2017-11-28 15:06:01 +01:00
parent 5690db42cd
commit 2eb7246f87
8 changed files with 110 additions and 16 deletions

View File

@ -7,6 +7,7 @@ import { Link } from "../shared/models/link.model";
import { GraphLayout } from "../shared/widgets/graph.widget"; import { GraphLayout } from "../shared/widgets/graph.widget";
import { Context } from "../../map/models/context"; import { Context } from "../../map/models/context";
import { Size } from "../shared/models/size.model"; import { Size } from "../shared/models/size.model";
import { Drawing } from "../shared/models/drawing.model";
@Component({ @Component({
@ -17,6 +18,7 @@ import { Size } from "../shared/models/size.model";
export class MapComponent implements OnInit, OnChanges, OnDestroy { export class MapComponent implements OnInit, OnChanges, OnDestroy {
@Input() nodes: Node[] = []; @Input() nodes: Node[] = [];
@Input() links: Link[] = []; @Input() links: Link[] = [];
@Input() drawings: Drawing[] = [];
@Input() width = 1500; @Input() width = 1500;
@Input() height = 600; @Input() height = 600;
@Input() phylloRadius = 7; @Input() phylloRadius = 7;
@ -43,6 +45,7 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
(changes['height'] && !changes['height'].isFirstChange()) || (changes['height'] && !changes['height'].isFirstChange()) ||
(changes['phylloRadius'] && !changes['phylloRadius'].isFirstChange()) || (changes['phylloRadius'] && !changes['phylloRadius'].isFirstChange()) ||
(changes['pointRadius'] && !changes['pointRadius'].isFirstChange()) || (changes['pointRadius'] && !changes['pointRadius'].isFirstChange()) ||
(changes['drawings'] && !changes['drawings'].isFirstChange()) ||
(changes['nodes'] && !changes['nodes'].isFirstChange()) || (changes['nodes'] && !changes['nodes'].isFirstChange()) ||
(changes['links'] && !changes['links'].isFirstChange()) (changes['links'] && !changes['links'].isFirstChange())
) { ) {
@ -115,6 +118,7 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
this.graphLayout.setNodes(this.nodes); this.graphLayout.setNodes(this.nodes);
this.graphLayout.setLinks(this.links); this.graphLayout.setLinks(this.links);
this.graphLayout.setDrawings(this.drawings);
this.redraw(); this.redraw();
} }

View File

@ -0,0 +1,9 @@
export class Drawing {
drawing_id: string;
project_id: string;
rotation: number;
svg: string;
x: number;
y: number;
z: number;
}

View File

@ -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<SVGGElement, Drawing>('g.drawing')
.data(drawings);
const drawing_enter = drawing.enter()
.append<SVGGElement>('g')
.attr('class', 'drawing');
const parser = new DOMParser();
const drawing_image = drawing_enter.append<SVGImageElement>('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) {
}
}

View File

@ -7,14 +7,18 @@ import { SVGSelection } from "../../../map/models/types";
import { LinksWidget } from "./links.widget"; import { LinksWidget } from "./links.widget";
import { D3ZoomEvent, zoom } from "d3-zoom"; import { D3ZoomEvent, zoom } from "d3-zoom";
import { event } from "d3-selection"; import { event } from "d3-selection";
import {Drawing} from "../models/drawing.model";
import {DrawingsWidget} from "./drawings.widget";
export class GraphLayout implements Widget { export class GraphLayout implements Widget {
private nodes: Node[] = []; private nodes: Node[] = [];
private links: Link[] = []; private links: Link[] = [];
private drawings: Drawing[] = [];
private nodesWidget = new NodesWidget(); private nodesWidget = new NodesWidget();
private linksWidget = new LinksWidget(); private linksWidget = new LinksWidget();
private drawingsWidget = new DrawingsWidget();
private centerZeroZeroPoint = true; private centerZeroZeroPoint = true;
@ -26,42 +30,46 @@ export class GraphLayout implements Widget {
this.links = links; this.links = links;
} }
public setDrawings(drawings: Drawing[]) {
this.drawings = drawings;
}
draw(view: SVGSelection, context: Context) { draw(view: SVGSelection, context: Context) {
const self = this; const self = this;
const drawing = view const canvas = view
.selectAll<SVGGElement, Context>('g.drawing') .selectAll<SVGGElement, Context>('g.canvas')
.data([context]); .data([context]);
const drawingEnter = drawing.enter() const canvasEnter = canvas.enter()
.append<SVGGElement>('g') .append<SVGGElement>('g')
.attr('class', 'drawing'); .attr('class', 'canvas');
if (this.centerZeroZeroPoint) { if (this.centerZeroZeroPoint) {
drawing.attr( canvas.attr(
'transform', 'transform',
(ctx: Context) => `translate(${ctx.getSize().width / 2}, ${ctx.getSize().height / 2})`); (ctx: Context) => `translate(${ctx.getSize().width / 2}, ${ctx.getSize().height / 2})`);
} }
const links = drawingEnter.append<SVGGElement>('g') // const links = canvasEnter.append<SVGGElement>('g')
.attr('class', 'links'); // .attr('class', 'links');
//
// const nodes = canvasEnter.append<SVGGElement>('g')
// .attr('class', 'nodes');
const nodes = drawingEnter.append<SVGGElement>('g') this.linksWidget.draw(canvas, this.links);
.attr('class', 'nodes'); this.nodesWidget.draw(canvas, this.nodes);
this.drawingsWidget.draw(canvas, this.drawings)
this.linksWidget.draw(drawing, this.links);
this.nodesWidget.draw(drawing, this.nodes);
const onZoom = function(this: SVGSVGElement) { const onZoom = function(this: SVGSVGElement) {
const e: D3ZoomEvent<SVGSVGElement, any> = event; const e: D3ZoomEvent<SVGSVGElement, any> = event;
if (self.centerZeroZeroPoint) { if (self.centerZeroZeroPoint) {
drawing.attr( canvas.attr(
'transform', 'transform',
`translate(${context.getSize().width / 2 + e.transform.x}, ` + `translate(${context.getSize().width / 2 + e.transform.x}, ` +
`${context.getSize().height / 2 + e.transform.y}) scale(${e.transform.k})`); `${context.getSize().height / 2 + e.transform.y}) scale(${e.transform.k})`);
} else { } else {
drawing.attr('transform', e.transform.toString()); canvas.attr('transform', e.transform.toString());
} }
}; };

View File

@ -1 +1 @@
<svg preserveAspectRatio="none"></svg> <svg xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="none"></svg>

Before

Width:  |  Height:  |  Size: 39 B

After

Width:  |  Height:  |  Size: 83 B

View File

@ -1,5 +1,5 @@
<div *ngIf="project" class="project-map"> <div *ngIf="project" class="project-map">
<app-map [nodes]="nodes" [links]="links"></app-map> <app-map [nodes]="nodes" [links]="links" [drawings]="drawings"></app-map>
<div class="project-toolbar"> <div class="project-toolbar">
<mat-toolbar color="primary" class="project-toolbar"> <mat-toolbar color="primary" class="project-toolbar">

View File

@ -25,6 +25,7 @@ import { Snapshot } from "../shared/models/snapshot";
import { ProgressDialogService } from "../shared/progress-dialog/progress-dialog.service"; import { ProgressDialogService } from "../shared/progress-dialog/progress-dialog.service";
import { ProgressDialogComponent } from "../shared/progress-dialog/progress-dialog.component"; import { ProgressDialogComponent } from "../shared/progress-dialog/progress-dialog.component";
import { ToastyService } from "ng2-toasty"; import { ToastyService } from "ng2-toasty";
import {Drawing} from "../cartography/shared/models/drawing.model";
@Component({ @Component({
@ -36,6 +37,7 @@ import { ToastyService } from "ng2-toasty";
export class ProjectMapComponent implements OnInit { export class ProjectMapComponent implements OnInit {
public nodes: Node[] = []; public nodes: Node[] = [];
public links: Link[] = []; public links: Link[] = [];
public drawings: Drawing[] = [];
project: Project; project: Project;
server: Server; server: Server;
@ -86,6 +88,10 @@ export class ProjectMapComponent implements OnInit {
this.symbolService this.symbolService
.load(this.server) .load(this.server)
.flatMap(() => { .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); return this.projectService.links(this.server, project.project_id);
}) })
.flatMap((links: Link[]) => { .flatMap((links: Link[]) => {

View File

@ -7,6 +7,7 @@ import 'rxjs/add/operator/map';
import { Link } from "../../cartography/shared/models/link.model"; import { Link } from "../../cartography/shared/models/link.model";
import { Server } from "../models/server"; import { Server } from "../models/server";
import { HttpServer } from "./http-server.service"; import { HttpServer } from "./http-server.service";
import {Drawing} from "../../cartography/shared/models/drawing.model";
@Injectable() @Injectable()
export class ProjectService { export class ProjectService {
@ -43,6 +44,12 @@ export class ProjectService {
.map(response => response.json() as Link[]); .map(response => response.json() as Link[]);
} }
drawings(server: Server, project_id: string): Observable<Drawing[]> {
return this.httpServer
.get(server, `/projects/${project_id}/drawings`)
.map(response => response.json() as Drawing[]);
}
delete(server: Server, project_id: string): Observable<any> { delete(server: Server, project_id: string): Observable<any> {
return this.httpServer return this.httpServer
.delete(server, `/projects/${project_id}`); .delete(server, `/projects/${project_id}`);