mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-02-22 18:22:35 +00:00
Initial implementation of text editing
This commit is contained in:
parent
acac9edf0e
commit
c0bfc3ed35
@ -5,6 +5,7 @@ import { MapDrawing } from '../../models/map/map-drawing';
|
|||||||
import { RectElement } from '../../models/drawings/rect-element';
|
import { RectElement } from '../../models/drawings/rect-element';
|
||||||
import { EllipseElement } from '../../models/drawings/ellipse-element';
|
import { EllipseElement } from '../../models/drawings/ellipse-element';
|
||||||
import { LineElement } from '../../models/drawings/line-element';
|
import { LineElement } from '../../models/drawings/line-element';
|
||||||
|
import { TextElement } from '../../models/drawings/text-element';
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -21,6 +22,8 @@ export class MapDrawingToSvgConverter implements Converter<MapDrawing, string> {
|
|||||||
elem = `<ellipse fill=\"${mapDrawing.element.fill}\" fill-opacity=\"${mapDrawing.element.fill_opacity}\" cx=\"${mapDrawing.element.cx}\" cy=\"${mapDrawing.element.cy}\" rx=\"${mapDrawing.element.rx}\" ry=\"${mapDrawing.element.ry}\" stroke=\"${mapDrawing.element.stroke}\" stroke-width=\"${mapDrawing.element.stroke_width}\" />`;
|
elem = `<ellipse fill=\"${mapDrawing.element.fill}\" fill-opacity=\"${mapDrawing.element.fill_opacity}\" cx=\"${mapDrawing.element.cx}\" cy=\"${mapDrawing.element.cy}\" rx=\"${mapDrawing.element.rx}\" ry=\"${mapDrawing.element.ry}\" stroke=\"${mapDrawing.element.stroke}\" stroke-width=\"${mapDrawing.element.stroke_width}\" />`;
|
||||||
} else if (mapDrawing.element instanceof LineElement) {
|
} else if (mapDrawing.element instanceof LineElement) {
|
||||||
elem = `<line stroke=\"${mapDrawing.element.stroke}\" stroke-width=\"${mapDrawing.element.stroke_width}\" x1=\"${mapDrawing.element.x1}\" x2=\"${mapDrawing.element.x2}\" y1=\"${mapDrawing.element.y1}\" y2=\"${mapDrawing.element.y2}\" />`
|
elem = `<line stroke=\"${mapDrawing.element.stroke}\" stroke-width=\"${mapDrawing.element.stroke_width}\" x1=\"${mapDrawing.element.x1}\" x2=\"${mapDrawing.element.x2}\" y1=\"${mapDrawing.element.y1}\" y2=\"${mapDrawing.element.y2}\" />`
|
||||||
|
} else if (mapDrawing.element instanceof TextElement) {
|
||||||
|
elem = `<text fill=\"${mapDrawing.element.fill}\" fill-opacity=\"${mapDrawing.element.fill_opacity}\" font-family=\"${mapDrawing.element.font_family}\" font-size=\"${mapDrawing.element.font_size}\" font-weight=\"${mapDrawing.element.font_weight}\">${mapDrawing.element.text}</text>`;
|
||||||
} else return "";
|
} else return "";
|
||||||
|
|
||||||
return `<svg height=\"${mapDrawing.element.height}\" width=\"${mapDrawing.element.width}\">${elem}</svg>`;
|
return `<svg height=\"${mapDrawing.element.height}\" width=\"${mapDrawing.element.width}\">${elem}</svg>`;
|
||||||
|
@ -14,8 +14,8 @@ export class ResizedDataEvent<T> {
|
|||||||
public x: number,
|
public x: number,
|
||||||
public y: number,
|
public y: number,
|
||||||
public width: number,
|
public width: number,
|
||||||
public height: number) {
|
public height: number
|
||||||
}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ClickedDataEvent<T> {
|
export class ClickedDataEvent<T> {
|
||||||
@ -24,4 +24,11 @@ export class ClickedDataEvent<T> {
|
|||||||
public x: number,
|
public x: number,
|
||||||
public y: number
|
public y: number
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class EditedDataEvent {
|
||||||
|
constructor(
|
||||||
|
public id: string,
|
||||||
|
public editedText: string
|
||||||
|
) {}
|
||||||
|
}
|
||||||
|
@ -24,6 +24,8 @@ export class SelectionManager {
|
|||||||
this.selection = dictItems;
|
this.selection = dictItems;
|
||||||
|
|
||||||
if (selected.length > 0) {
|
if (selected.length > 0) {
|
||||||
|
//console.log(selected);
|
||||||
|
|
||||||
this.selected.emit(selected);
|
this.selected.emit(selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@ export class SelectionTool {
|
|||||||
private activate(selection) {
|
private activate(selection) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
|
console.log("test!!!", selection);
|
||||||
|
|
||||||
selection.on("mousedown", function() {
|
selection.on("mousedown", function() {
|
||||||
const subject = select(window);
|
const subject = select(window);
|
||||||
const parent = this.parentElement;
|
const parent = this.parentElement;
|
||||||
|
18
src/app/cartography/tools/text-editing-tool.ts
Normal file
18
src/app/cartography/tools/text-editing-tool.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Injectable, EventEmitter } from "@angular/core";
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TextEditingTool {
|
||||||
|
static readonly EDITING_CLASS = '.text-editing';
|
||||||
|
|
||||||
|
private enabled = true;
|
||||||
|
public editingFinished = new EventEmitter<any>();
|
||||||
|
|
||||||
|
public setEnabled(enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public activate(){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -24,10 +24,91 @@ export class TextDrawingWidget implements DrawingShapeWidget {
|
|||||||
return (d.element && d.element instanceof TextElement) ? [d.element] : [];
|
return (d.element && d.element instanceof TextElement) ? [d.element] : [];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// drawing.enter()
|
||||||
|
// .append("foreignObject")
|
||||||
|
// .attr("width", (elem) => elem.width)
|
||||||
|
// .attr("height", (elem) => elem.height)
|
||||||
|
// .attr("visibility", "hidden")
|
||||||
|
// .append("xhtml:div")
|
||||||
|
// .attr("width", (elem) => elem.width)
|
||||||
|
// .attr("height", (elem) => elem.height)
|
||||||
|
// .attr('style', (text: TextElement) => {
|
||||||
|
// const font = this.fontFixer.fix(text);
|
||||||
|
|
||||||
|
// const styles: string[] = [];
|
||||||
|
// if (font.font_family) {
|
||||||
|
// styles.push(`font-family: "${text.font_family}"`);
|
||||||
|
// }
|
||||||
|
// if (font.font_size) {
|
||||||
|
// styles.push(`font-size: ${text.font_size}pt`);
|
||||||
|
// }
|
||||||
|
// if (font.font_weight) {
|
||||||
|
// styles.push(`font-weight: ${text.font_weight}`);
|
||||||
|
// }
|
||||||
|
// styles.push(`color: ${text.fill}`);
|
||||||
|
// return styles.join("; ");
|
||||||
|
// })
|
||||||
|
// .attr('text-decoration', (text) => text.text_decoration)
|
||||||
|
// .attr('contenteditable', 'true')
|
||||||
|
// .text((elem) => elem.text)
|
||||||
|
// .on("dblclick", (_, index, textElements) => {
|
||||||
|
// select(textElements[index]).attr("visibility", "visible");
|
||||||
|
// });
|
||||||
|
|
||||||
const drawing_enter = drawing
|
const drawing_enter = drawing
|
||||||
.enter()
|
.enter()
|
||||||
.append<SVGTextElement>('text')
|
.append<SVGTextElement>('text')
|
||||||
.attr('class', 'text_element noselect');
|
.attr('class', 'text_element noselect')
|
||||||
|
.on("dblclick", (elem, index, textElements) => {
|
||||||
|
console.log("Id: ", textElements[index].parentElement.parentElement.getAttribute("drawing_id"));
|
||||||
|
|
||||||
|
select(textElements[index])
|
||||||
|
.attr("visibility", "hidden");
|
||||||
|
|
||||||
|
select(textElements[index])
|
||||||
|
.classed("editingMode", true);
|
||||||
|
|
||||||
|
select(textElements[index].parentElement.parentElement.parentElement)
|
||||||
|
.append("foreignObject")
|
||||||
|
.attr("width", '1000px')
|
||||||
|
.attr("min-width", 'fit-content')
|
||||||
|
.attr("height", '100px')
|
||||||
|
.attr("id", "temporaryText")
|
||||||
|
.attr("transform", textElements[index].parentElement.getAttribute("transform"))
|
||||||
|
.append("xhtml:div")
|
||||||
|
.attr("width", "fit-content")
|
||||||
|
.attr("height", "fit-content")
|
||||||
|
.attr("class", "temporaryTextInside")
|
||||||
|
.attr('style', () => {
|
||||||
|
const styles: string[] = [];
|
||||||
|
styles.push(`white-space: pre-line`)
|
||||||
|
styles.push(`outline: 0px solid transparent`)
|
||||||
|
styles.push(`font-family: ${elem.font_family}`)
|
||||||
|
styles.push(`font-size: ${elem.font_size}pt!important`);
|
||||||
|
styles.push(`font-weight: ${elem.font_weight}`)
|
||||||
|
styles.push(`color: ${elem.fill}`);
|
||||||
|
return styles.join("; ");
|
||||||
|
})
|
||||||
|
.attr('text-decoration', elem.text_decoration)
|
||||||
|
.attr('contenteditable', 'true')
|
||||||
|
.text(elem.text)
|
||||||
|
.on("focusout", (elem, index, textElements) => {
|
||||||
|
let temporaryText = document.getElementsByClassName("temporaryTextInside")[0] as HTMLElement;
|
||||||
|
let savedText = temporaryText.innerText;
|
||||||
|
|
||||||
|
//let splittedText = savedText.split(/\r?\n/);
|
||||||
|
var temporaryElement = document.getElementById("temporaryText") as HTMLElement;
|
||||||
|
temporaryElement.remove();
|
||||||
|
|
||||||
|
view.selectAll<SVGTextElement, TextElement>('text.editingMode')
|
||||||
|
.attr("visibility", "visible")
|
||||||
|
.classed("editingMode", false)
|
||||||
|
.text(savedText);
|
||||||
|
});
|
||||||
|
|
||||||
|
var txtInside = document.getElementsByClassName("temporaryTextInside")[0] as HTMLElement;
|
||||||
|
txtInside.focus();
|
||||||
|
});
|
||||||
|
|
||||||
const merge = drawing.merge(drawing_enter);
|
const merge = drawing.merge(drawing_enter);
|
||||||
merge
|
merge
|
||||||
@ -75,6 +156,7 @@ export class TextDrawingWidget implements DrawingShapeWidget {
|
|||||||
// approx and make it matching to GUI
|
// approx and make it matching to GUI
|
||||||
const tspan = select(this).selectAll<SVGTSpanElement, string>('tspan');
|
const tspan = select(this).selectAll<SVGTSpanElement, string>('tspan');
|
||||||
const height = this.getBBox().height / tspan.size();
|
const height = this.getBBox().height / tspan.size();
|
||||||
|
//return `translate(0, ${height})`;
|
||||||
return `translate(${TextDrawingWidget.MARGIN}, ${height - TextDrawingWidget.MARGIN})`;
|
return `translate(${TextDrawingWidget.MARGIN}, ${height - TextDrawingWidget.MARGIN})`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ g.node:hover {
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
left: 92px;
|
left: 92px;
|
||||||
width: 232px !important;
|
width: 296px !important;
|
||||||
height: 72px !important;
|
height: 72px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ g.node:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.drawer {
|
.drawer {
|
||||||
width: 232px !important;
|
width: 296px !important;
|
||||||
height: 72px !important;
|
height: 72px !important;
|
||||||
background:#263238;
|
background:#263238;
|
||||||
}
|
}
|
||||||
@ -51,7 +51,6 @@ g.node:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.drawer-button {
|
.drawer-button {
|
||||||
height: 72px;
|
|
||||||
width: 64px!important;
|
width: 64px!important;
|
||||||
background: #263238;
|
background: #263238;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@ -70,8 +69,7 @@ g.node:hover {
|
|||||||
|
|
||||||
.drawer-arrow-button-left {
|
.drawer-arrow-button-left {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 72px;
|
margin-left: 256px;
|
||||||
margin-left: 192px;
|
|
||||||
background:#263238;
|
background:#263238;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,9 @@
|
|||||||
<mat-drawer-container [ngClass]="{shadow: drawTools.visibility}" class="drawer-container">
|
<mat-drawer-container [ngClass]="{shadow: drawTools.visibility}" class="drawer-container">
|
||||||
<mat-drawer #drawer class="drawer">
|
<mat-drawer #drawer class="drawer">
|
||||||
<div class="drawer-buttons">
|
<div class="drawer-buttons">
|
||||||
|
<button matTooltip="Add a note" mat-icon-button class="drawer-button" [color]="drawTools.isAddingTextChosen ? 'primary': 'basic'" (click)="addText()">
|
||||||
|
<mat-icon>create</mat-icon>
|
||||||
|
</button>
|
||||||
<button matTooltip="Draw a rectangle" mat-icon-button class="drawer-button" [color]="drawTools.isRectangleChosen ? 'primary': 'basic'" (click)="addDrawing('rectangle')">
|
<button matTooltip="Draw a rectangle" mat-icon-button class="drawer-button" [color]="drawTools.isRectangleChosen ? 'primary': 'basic'" (click)="addDrawing('rectangle')">
|
||||||
<mat-icon>crop_3_2</mat-icon>
|
<mat-icon>crop_3_2</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
@ -79,7 +79,7 @@ export class MockedDrawingsDataSource {
|
|||||||
update() { return of({})}
|
update() { return of({})}
|
||||||
}
|
}
|
||||||
|
|
||||||
fdescribe('ProjectMapComponent', () => {
|
describe('ProjectMapComponent', () => {
|
||||||
let component: ProjectMapComponent;
|
let component: ProjectMapComponent;
|
||||||
let fixture: ComponentFixture<ProjectMapComponent>;
|
let fixture: ComponentFixture<ProjectMapComponent>;
|
||||||
let drawingService = new MockedDrawingService;
|
let drawingService = new MockedDrawingService;
|
||||||
|
@ -27,7 +27,7 @@ import { MapChangeDetectorRef } from '../../cartography/services/map-change-dete
|
|||||||
import { NodeContextMenu } from '../../cartography/events/nodes';
|
import { NodeContextMenu } from '../../cartography/events/nodes';
|
||||||
import { MapLinkCreated } from '../../cartography/events/links';
|
import { MapLinkCreated } from '../../cartography/events/links';
|
||||||
import { NodeWidget } from '../../cartography/widgets/node';
|
import { NodeWidget } from '../../cartography/widgets/node';
|
||||||
import { DraggedDataEvent, ResizedDataEvent } from '../../cartography/events/event-source';
|
import { DraggedDataEvent, ResizedDataEvent, EditedDataEvent } from '../../cartography/events/event-source';
|
||||||
import { DrawingService } from '../../services/drawing.service';
|
import { DrawingService } from '../../services/drawing.service';
|
||||||
import { MapNodeToNodeConverter } from '../../cartography/converters/map/map-node-to-node-converter';
|
import { MapNodeToNodeConverter } from '../../cartography/converters/map/map-node-to-node-converter';
|
||||||
import { NodesEventSource } from '../../cartography/events/nodes-event-source';
|
import { NodesEventSource } from '../../cartography/events/nodes-event-source';
|
||||||
@ -45,6 +45,9 @@ import { SettingsService, Settings } from '../../services/settings.service';
|
|||||||
import { MapLabel } from '../../cartography/models/map/map-label';
|
import { MapLabel } from '../../cartography/models/map/map-label';
|
||||||
import { D3MapComponent } from '../../cartography/components/d3-map/d3-map.component';
|
import { D3MapComponent } from '../../cartography/components/d3-map/d3-map.component';
|
||||||
import { MapLinkNode } from '../../cartography/models/map/map-link-node';
|
import { MapLinkNode } from '../../cartography/models/map/map-link-node';
|
||||||
|
import { TextElement } from '../../cartography/models/drawings/text-element';
|
||||||
|
import { select } from 'd3-selection';
|
||||||
|
import { FontFixer } from '../../cartography/helpers/font-fixer';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -75,7 +78,8 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
'isRectangleChosen': false,
|
'isRectangleChosen': false,
|
||||||
'isEllipseChosen': false,
|
'isEllipseChosen': false,
|
||||||
'isLineChosen': false,
|
'isLineChosen': false,
|
||||||
'visibility': false
|
'visibility': false,
|
||||||
|
'isAddingTextChosen': false
|
||||||
};
|
};
|
||||||
|
|
||||||
protected selectedDrawing: string;
|
protected selectedDrawing: string;
|
||||||
@ -344,6 +348,10 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onDrawingEdited(editedEvent: EditedDataEvent){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public set readonly(value) {
|
public set readonly(value) {
|
||||||
this.inReadOnlyMode = value;
|
this.inReadOnlyMode = value;
|
||||||
if (value) {
|
if (value) {
|
||||||
@ -382,16 +390,19 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
switch (selectedObject) {
|
switch (selectedObject) {
|
||||||
case "rectangle":
|
case "rectangle":
|
||||||
|
this.drawTools.isAddingTextChosen = false;
|
||||||
this.drawTools.isEllipseChosen = false;
|
this.drawTools.isEllipseChosen = false;
|
||||||
this.drawTools.isRectangleChosen = !this.drawTools.isRectangleChosen;
|
this.drawTools.isRectangleChosen = !this.drawTools.isRectangleChosen;
|
||||||
this.drawTools.isLineChosen = false;
|
this.drawTools.isLineChosen = false;
|
||||||
break;
|
break;
|
||||||
case "ellipse":
|
case "ellipse":
|
||||||
|
this.drawTools.isAddingTextChosen = false;
|
||||||
this.drawTools.isEllipseChosen = !this.drawTools.isEllipseChosen;
|
this.drawTools.isEllipseChosen = !this.drawTools.isEllipseChosen;
|
||||||
this.drawTools.isRectangleChosen = false;
|
this.drawTools.isRectangleChosen = false;
|
||||||
this.drawTools.isLineChosen = false;
|
this.drawTools.isLineChosen = false;
|
||||||
break;
|
break;
|
||||||
case "line":
|
case "line":
|
||||||
|
this.drawTools.isAddingTextChosen = false;
|
||||||
this.drawTools.isEllipseChosen = false;
|
this.drawTools.isEllipseChosen = false;
|
||||||
this.drawTools.isRectangleChosen = false;
|
this.drawTools.isRectangleChosen = false;
|
||||||
this.drawTools.isLineChosen = !this.drawTools.isLineChosen;
|
this.drawTools.isLineChosen = !this.drawTools.isLineChosen;
|
||||||
@ -424,6 +435,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.drawTools.isRectangleChosen = false;
|
this.drawTools.isRectangleChosen = false;
|
||||||
this.drawTools.isEllipseChosen = false;
|
this.drawTools.isEllipseChosen = false;
|
||||||
this.drawTools.isLineChosen = false;
|
this.drawTools.isLineChosen = false;
|
||||||
|
this.drawTools.isAddingTextChosen = false;
|
||||||
this.selectedDrawing = "";
|
this.selectedDrawing = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,45 +450,58 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
this.drawTools.visibility = true;
|
this.drawTools.visibility = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDrawingMock(objectType: string): MapDrawing {
|
public getDrawingMock(objectType: string, text?: string): MapDrawing {
|
||||||
let drawingElement: DrawingElement;
|
let drawingElement: DrawingElement;
|
||||||
|
|
||||||
switch (objectType) {
|
switch (objectType) {
|
||||||
case "rectangle":
|
case "rectangle":
|
||||||
let rect = new RectElement();
|
let rectElement = new RectElement();
|
||||||
rect.fill = "#ffffff";
|
rectElement.fill = "#ffffff";
|
||||||
rect.fill_opacity = 1.0;
|
rectElement.fill_opacity = 1.0;
|
||||||
rect.stroke = "#000000";
|
rectElement.stroke = "#000000";
|
||||||
rect.stroke_width = 2;
|
rectElement.stroke_width = 2;
|
||||||
rect.width = 200;
|
rectElement.width = 200;
|
||||||
rect.height = 100;
|
rectElement.height = 100;
|
||||||
drawingElement = rect;
|
drawingElement = rectElement;
|
||||||
break;
|
break;
|
||||||
case "ellipse":
|
case "ellipse":
|
||||||
let ellipse = new EllipseElement();
|
let ellipseElement = new EllipseElement();
|
||||||
ellipse.fill = "#ffffff";
|
ellipseElement.fill = "#ffffff";
|
||||||
ellipse.fill_opacity = 1.0;
|
ellipseElement.fill_opacity = 1.0;
|
||||||
ellipse.stroke = "#000000";
|
ellipseElement.stroke = "#000000";
|
||||||
ellipse.stroke_width = 2;
|
ellipseElement.stroke_width = 2;
|
||||||
ellipse.cx = 100;
|
ellipseElement.cx = 100;
|
||||||
ellipse.cy = 100;
|
ellipseElement.cy = 100;
|
||||||
ellipse.rx = 100;
|
ellipseElement.rx = 100;
|
||||||
ellipse.ry = 100;
|
ellipseElement.ry = 100;
|
||||||
ellipse.width = 200;
|
ellipseElement.width = 200;
|
||||||
ellipse.height = 200;
|
ellipseElement.height = 200;
|
||||||
drawingElement = ellipse;
|
drawingElement = ellipseElement;
|
||||||
break;
|
break;
|
||||||
case "line":
|
case "line":
|
||||||
let line = new LineElement();
|
let lineElement = new LineElement();
|
||||||
line.stroke = "#000000";
|
lineElement.stroke = "#000000";
|
||||||
line.stroke_width = 2;
|
lineElement.stroke_width = 2;
|
||||||
line.x1 = 0;
|
lineElement.x1 = 0;
|
||||||
line.x2 = 200;
|
lineElement.x2 = 200;
|
||||||
line.y1 = 0;
|
lineElement.y1 = 0;
|
||||||
line.y2 = 0;
|
lineElement.y2 = 0;
|
||||||
line.width = 100;
|
lineElement.width = 100;
|
||||||
line.height = 0;
|
lineElement.height = 0;
|
||||||
drawingElement = line;
|
drawingElement = lineElement;
|
||||||
|
break;
|
||||||
|
case "text":
|
||||||
|
let textElement = new TextElement();
|
||||||
|
textElement.height = 100; //should be calculated
|
||||||
|
textElement.width = 100;
|
||||||
|
textElement.text = text;
|
||||||
|
textElement.fill = "#000000";
|
||||||
|
textElement.fill_opacity = 0;
|
||||||
|
textElement.font_family = "Noto Sans";
|
||||||
|
textElement.font_size = 11;
|
||||||
|
textElement.font_weight = "bold";
|
||||||
|
drawingElement = textElement;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mapDrawing = new MapDrawing();
|
let mapDrawing = new MapDrawing();
|
||||||
@ -484,6 +509,68 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
|||||||
return mapDrawing;
|
return mapDrawing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addText(){
|
||||||
|
if (!this.drawTools.isAddingTextChosen){
|
||||||
|
this.resetDrawToolChoice();
|
||||||
|
this.drawTools.isAddingTextChosen = true;
|
||||||
|
var map = document.getElementsByClassName('map')[0];
|
||||||
|
|
||||||
|
let addTextListener = (event: MouseEvent) => {
|
||||||
|
let x = event.clientX - this.mapChild.context.getZeroZeroTransformationPoint().x;
|
||||||
|
let y = event.clientY - this.mapChild.context.getZeroZeroTransformationPoint().y;
|
||||||
|
|
||||||
|
const svgElement = select("g.canvas");
|
||||||
|
svgElement
|
||||||
|
.append("foreignObject")
|
||||||
|
.attr("id", "temporaryText")
|
||||||
|
.attr("transform", `translate(${x},${y}) rotate(0)`)
|
||||||
|
.attr("width", '1000px')
|
||||||
|
.append("xhtml:div")
|
||||||
|
.attr("class", "temporaryTextInside")
|
||||||
|
.attr('style', () => {
|
||||||
|
const styles: string[] = [];
|
||||||
|
styles.push(`font-family: Noto Sans`)
|
||||||
|
styles.push(`font-size: 11pt`);
|
||||||
|
styles.push(`font-weight: bold`)
|
||||||
|
styles.push(`color: #000000`);
|
||||||
|
return styles.join("; ");
|
||||||
|
})
|
||||||
|
.attr("width", 'fit-content')
|
||||||
|
.attr("height", 'max-content')
|
||||||
|
.attr('contenteditable', 'true')
|
||||||
|
.text("")
|
||||||
|
.on("focusout", () => {
|
||||||
|
let elem = document.getElementsByClassName("temporaryTextInside")[0] as HTMLElement;
|
||||||
|
let savedText = elem.innerText;
|
||||||
|
|
||||||
|
let drawing = this.getDrawingMock("text", savedText);
|
||||||
|
(drawing.element as TextElement).text = savedText;
|
||||||
|
let svgText = this.mapDrawingToSvgConverter.convert(drawing);
|
||||||
|
|
||||||
|
this.drawingService
|
||||||
|
.add(this.server, this.project.project_id, x, y, svgText)
|
||||||
|
.subscribe((serverDrawing: Drawing) => {
|
||||||
|
var temporaryElement = document.getElementById("temporaryText") as HTMLElement;
|
||||||
|
temporaryElement.remove();
|
||||||
|
this.drawingsDataSource.add(serverDrawing);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var elem = document.getElementsByClassName("temporaryTextInside")[0] as HTMLElement;
|
||||||
|
elem.focus();
|
||||||
|
this.resetDrawToolChoice();
|
||||||
|
}
|
||||||
|
|
||||||
|
map.removeEventListener('click', this.drawListener as EventListenerOrEventListenerObject);
|
||||||
|
this.drawListener = addTextListener;
|
||||||
|
map.addEventListener('click', this.drawListener as EventListenerOrEventListenerObject, {once : true});
|
||||||
|
} else {
|
||||||
|
this.resetDrawToolChoice();
|
||||||
|
var map = document.getElementsByClassName('map')[0];
|
||||||
|
map.removeEventListener('click', this.drawListener as EventListenerOrEventListenerObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public ngOnDestroy() {
|
public ngOnDestroy() {
|
||||||
this.drawingsDataSource.clear();
|
this.drawingsDataSource.clear();
|
||||||
this.nodesDataSource.clear();
|
this.nodesDataSource.clear();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user