mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2025-06-06 01:01:33 +00:00
Text editing moved to common component
This commit is contained in:
parent
af1957915b
commit
417cdfb105
@ -42,7 +42,6 @@ import { SelectionSelectComponent } from './components/selection-select/selectio
|
|||||||
import { DraggableSelectionComponent } from './components/draggable-selection/draggable-selection.component';
|
import { DraggableSelectionComponent } from './components/draggable-selection/draggable-selection.component';
|
||||||
import { MapSettingsManager } from './managers/map-settings-manager';
|
import { MapSettingsManager } from './managers/map-settings-manager';
|
||||||
import { DrawingResizingComponent } from './components/drawing-resizing/drawing-resizing.component';
|
import { DrawingResizingComponent } from './components/drawing-resizing/drawing-resizing.component';
|
||||||
import { TextEditingComponent } from './components/text-editing/text-editing.component';
|
|
||||||
import { FontBBoxCalculator } from './helpers/font-bbox-calculator';
|
import { FontBBoxCalculator } from './helpers/font-bbox-calculator';
|
||||||
import { StylesToFontConverter } from './converters/styles-to-font-converter';
|
import { StylesToFontConverter } from './converters/styles-to-font-converter';
|
||||||
import { TextElementFactory } from './helpers/drawings-factory/text-element-factory';
|
import { TextElementFactory } from './helpers/drawings-factory/text-element-factory';
|
||||||
@ -64,7 +63,6 @@ import { DrawingAddingComponent } from './components/drawing-adding/drawing-addi
|
|||||||
ExperimentalMapComponent,
|
ExperimentalMapComponent,
|
||||||
DrawingAddingComponent,
|
DrawingAddingComponent,
|
||||||
DrawingResizingComponent,
|
DrawingResizingComponent,
|
||||||
TextEditingComponent,
|
|
||||||
TemporaryTextElementComponent,
|
TemporaryTextElementComponent,
|
||||||
...ANGULAR_MAP_DECLARATIONS,
|
...ANGULAR_MAP_DECLARATIONS,
|
||||||
SelectionControlComponent,
|
SelectionControlComponent,
|
||||||
|
@ -12,6 +12,5 @@
|
|||||||
<app-drawing-resizing></app-drawing-resizing>
|
<app-drawing-resizing></app-drawing-resizing>
|
||||||
<app-selection-control></app-selection-control>
|
<app-selection-control></app-selection-control>
|
||||||
<app-selection-select></app-selection-select>
|
<app-selection-select></app-selection-select>
|
||||||
<app-temporary-text-element [svg]="svg"></app-temporary-text-element>
|
<app-temporary-text-element #temporaryTextElement [svg]="svg"></app-temporary-text-element>
|
||||||
<app-text-editing></app-text-editing>
|
|
||||||
<app-draggable-selection [svg]="svg"></app-draggable-selection>
|
<app-draggable-selection [svg]="svg"></app-draggable-selection>
|
||||||
|
Before Width: | Height: | Size: 534 B After Width: | Height: | Size: 518 B |
@ -18,9 +18,9 @@ import { Drawing } from '../../models/drawing';
|
|||||||
import { Symbol } from '../../../models/symbol';
|
import { Symbol } from '../../../models/symbol';
|
||||||
import { GraphDataManager } from '../../managers/graph-data-manager';
|
import { GraphDataManager } from '../../managers/graph-data-manager';
|
||||||
import { MapSettingsManager } from '../../managers/map-settings-manager';
|
import { MapSettingsManager } from '../../managers/map-settings-manager';
|
||||||
import { TextEditingTool } from '../../tools/text-editing-tool';
|
|
||||||
import { Server } from '../../../models/server';
|
import { Server } from '../../../models/server';
|
||||||
import { ToolsService } from '../../../services/tools.service';
|
import { ToolsService } from '../../../services/tools.service';
|
||||||
|
import { TemporaryTextElementComponent } from '../temporary-text-element/temporary-text-element.component';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -39,6 +39,7 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
@Input() height = 600;
|
@Input() height = 600;
|
||||||
|
|
||||||
@ViewChild('svg') svgRef: ElementRef;
|
@ViewChild('svg') svgRef: ElementRef;
|
||||||
|
@ViewChild('temporaryTextElement') temporaryTextElement: TemporaryTextElementComponent;
|
||||||
|
|
||||||
private parentNativeElement: any;
|
private parentNativeElement: any;
|
||||||
private svg: Selection<SVGSVGElement, any, null, undefined>;
|
private svg: Selection<SVGSVGElement, any, null, undefined>;
|
||||||
@ -62,7 +63,6 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
protected interfaceLabelWidget: InterfaceLabelWidget,
|
protected interfaceLabelWidget: InterfaceLabelWidget,
|
||||||
protected selectionToolWidget: SelectionTool,
|
protected selectionToolWidget: SelectionTool,
|
||||||
protected movingToolWidget: MovingTool,
|
protected movingToolWidget: MovingTool,
|
||||||
protected textEditingToolWidget: TextEditingTool,
|
|
||||||
public graphLayout: GraphLayout,
|
public graphLayout: GraphLayout,
|
||||||
private toolsService: ToolsService
|
private toolsService: ToolsService
|
||||||
) {
|
) {
|
||||||
@ -110,13 +110,6 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.subscriptions.push(
|
|
||||||
this.toolsService.isTextEditingToolActivated.subscribe((value: boolean) => {
|
|
||||||
this.textEditingToolWidget.setEnabled(value);
|
|
||||||
this.mapChangeDetectorRef.detectChanges();
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
this.subscriptions.push(
|
this.subscriptions.push(
|
||||||
this.toolsService.isMovingToolActivated.subscribe((value: boolean) => {
|
this.toolsService.isMovingToolActivated.subscribe((value: boolean) => {
|
||||||
this.movingToolWidget.setEnabled(value);
|
this.movingToolWidget.setEnabled(value);
|
||||||
@ -175,6 +168,7 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
this.graphDataManager.setLinks(this.links);
|
this.graphDataManager.setLinks(this.links);
|
||||||
this.graphDataManager.setDrawings(this.drawings);
|
this.graphDataManager.setDrawings(this.drawings);
|
||||||
this.graphLayout.draw(this.svg, this.context);
|
this.graphLayout.draw(this.svg, this.context);
|
||||||
|
this.temporaryTextElement.activateTextEditing();
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('window:resize', ['$event'])
|
@HostListener('window:resize', ['$event'])
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { Component, ViewChild, ElementRef, OnInit, Input, EventEmitter, OnDestroy } from "@angular/core";
|
import { Component, ViewChild, ElementRef, OnInit, Input, EventEmitter, OnDestroy } from "@angular/core";
|
||||||
import { DrawingsEventSource } from '../../events/drawings-event-source';
|
import { DrawingsEventSource } from '../../events/drawings-event-source';
|
||||||
import { TextAddedDataEvent } from '../../events/event-source';
|
import { TextAddedDataEvent, TextEditedDataEvent } from '../../events/event-source';
|
||||||
import { ToolsService } from '../../../services/tools.service';
|
import { ToolsService } from '../../../services/tools.service';
|
||||||
import { SVGSelection } from '../../models/types';
|
import { select } from 'd3-selection';
|
||||||
import { Selection, select } from 'd3-selection';
|
|
||||||
import { TextElement } from '../../models/drawings/text-element';
|
import { TextElement } from '../../models/drawings/text-element';
|
||||||
import { Context } from '../../models/context';
|
import { Context } from '../../models/context';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-temporary-text-element',
|
selector: 'app-temporary-text-element',
|
||||||
@ -16,18 +17,18 @@ export class TemporaryTextElementComponent implements OnInit, OnDestroy {
|
|||||||
@ViewChild('temporaryTextElement') temporaryTextElement: ElementRef;
|
@ViewChild('temporaryTextElement') temporaryTextElement: ElementRef;
|
||||||
@Input('svg') svg: SVGSVGElement;
|
@Input('svg') svg: SVGSVGElement;
|
||||||
|
|
||||||
private leftPosition: string = '0px';
|
private isActive: boolean = true;
|
||||||
private topPosition: string = '0px';
|
private leftPosition: string;
|
||||||
private innerText: string = '';
|
private topPosition: string;
|
||||||
private isActive: boolean = false;
|
private innerText: string = "";s
|
||||||
private mapListener: Function;
|
|
||||||
private textListener: Function;
|
|
||||||
public addingFinished = new EventEmitter<any>();
|
|
||||||
|
|
||||||
private enabled = true;
|
|
||||||
private editingDrawingId: string;
|
private editingDrawingId: string;
|
||||||
private editedElement: any;
|
private editedElement: any;
|
||||||
private temporaryElement: HTMLDivElement;
|
|
||||||
|
private mapListener: Function;
|
||||||
|
private textListener: Function;
|
||||||
|
private textAddingSubscription: Subscription;
|
||||||
|
public addingFinished = new EventEmitter<any>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private drawingsEventSource: DrawingsEventSource,
|
private drawingsEventSource: DrawingsEventSource,
|
||||||
@ -36,9 +37,9 @@ export class TemporaryTextElementComponent implements OnInit, OnDestroy {
|
|||||||
){}
|
){}
|
||||||
|
|
||||||
ngOnInit(){
|
ngOnInit(){
|
||||||
this.toolsService.isTextAddingToolActivated.subscribe((isActive: boolean) => {
|
this.textAddingSubscription = this.toolsService.isTextAddingToolActivated.subscribe((isActive: boolean) => {
|
||||||
this.isActive = isActive;
|
this.isActive = isActive;
|
||||||
isActive ? this.activate() : this.deactivate()
|
this.isActive ? this.activate() : this.deactivate()
|
||||||
});
|
});
|
||||||
|
|
||||||
this.activateTextEditing();
|
this.activateTextEditing();
|
||||||
@ -48,13 +49,13 @@ export class TemporaryTextElementComponent implements OnInit, OnDestroy {
|
|||||||
let addTextListener = (event: MouseEvent) => {
|
let addTextListener = (event: MouseEvent) => {
|
||||||
this.leftPosition = event.clientX.toString() + 'px';
|
this.leftPosition = event.clientX.toString() + 'px';
|
||||||
this.topPosition = event.clientY.toString() + 'px';
|
this.topPosition = event.clientY.toString() + 'px';
|
||||||
|
|
||||||
this.temporaryTextElement.nativeElement.focus();
|
this.temporaryTextElement.nativeElement.focus();
|
||||||
|
|
||||||
let textListener = () => {
|
let textListener = () => {
|
||||||
this.drawingsEventSource.textAdded.emit(new TextAddedDataEvent(this.temporaryTextElement.nativeElement.innerText.replace(/\n$/, ""), event.clientX, event.clientY));
|
this.drawingsEventSource.textAdded.emit(new TextAddedDataEvent(this.temporaryTextElement.nativeElement.innerText.replace(/\n$/, ""), event.clientX, event.clientY));
|
||||||
this.deactivate();
|
this.deactivate();
|
||||||
this.temporaryTextElement.nativeElement.removeEventListener('focusout', this.textListener);
|
this.temporaryTextElement.nativeElement.removeEventListener('focusout', this.textListener);
|
||||||
this.isActive = false;
|
|
||||||
}
|
}
|
||||||
this.textListener = textListener;
|
this.textListener = textListener;
|
||||||
this.temporaryTextElement.nativeElement.addEventListener('focusout', this.textListener);
|
this.temporaryTextElement.nativeElement.addEventListener('focusout', this.textListener);
|
||||||
@ -71,16 +72,38 @@ export class TemporaryTextElementComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
activateTextEditing(){
|
activateTextEditing(){
|
||||||
const rootElement = select(this.svg);
|
const rootElement = select(this.svg);
|
||||||
console.log("From component ", rootElement.selectAll<SVGTextElement, TextElement>('text.text_element'));
|
|
||||||
|
|
||||||
rootElement.selectAll<SVGTextElement, TextElement>('text.text_element')
|
rootElement.selectAll<SVGTextElement, TextElement>('text.text_element')
|
||||||
.on("dblclick", (elem, index, textElements) => {
|
.on("dblclick", (elem, index, textElements) => {
|
||||||
|
this.isActive = true;
|
||||||
this.editedElement = elem;
|
this.editedElement = elem;
|
||||||
|
|
||||||
select(textElements[index])
|
select(textElements[index])
|
||||||
.attr("visibility", "hidden");
|
.attr("visibility", "hidden");
|
||||||
|
|
||||||
select(textElements[index])
|
select(textElements[index])
|
||||||
.classed("editingMode", true);
|
.classed("editingMode", true);
|
||||||
|
|
||||||
|
this.editingDrawingId = textElements[index].parentElement.parentElement.getAttribute("drawing_id");
|
||||||
|
var transformData = textElements[index].parentElement.getAttribute("transform").split(/\(|\)/);
|
||||||
|
var x = Number(transformData[1].split(/,/)[0]) + this.context.getZeroZeroTransformationPoint().x;
|
||||||
|
var y = Number(transformData[1].split(/,/)[1]) + this.context.getZeroZeroTransformationPoint().y;
|
||||||
|
this.leftPosition = x.toString() + 'px';
|
||||||
|
this.topPosition = y.toString() + 'px';
|
||||||
|
this.innerText = elem.text;
|
||||||
|
|
||||||
|
this.temporaryTextElement.nativeElement.addEventListener("focusout", () => {
|
||||||
|
let innerText = this.temporaryTextElement.nativeElement.innerText;
|
||||||
|
this.drawingsEventSource.textEdited.emit(new TextEditedDataEvent(this.editingDrawingId, innerText.replace(/\n$/, ""), this.editedElement));
|
||||||
|
|
||||||
|
rootElement.selectAll<SVGTextElement, TextElement>('text.editingMode')
|
||||||
|
.attr("visibility", "visible")
|
||||||
|
.classed("editingMode", false);
|
||||||
|
|
||||||
|
this.isActive = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.temporaryTextElement.nativeElement.focus();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
|
||||||
import { Subscription } from 'rxjs';
|
|
||||||
import { TextEditingTool } from '../../tools/text-editing-tool';
|
|
||||||
import { DrawingsEventSource } from '../../events/drawings-event-source';
|
|
||||||
import { TextEditedDataEvent } from '../../events/event-source';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-text-editing',
|
|
||||||
template: `<ng-content></ng-content>`,
|
|
||||||
styleUrls: ['./text-editing.component.scss']
|
|
||||||
})
|
|
||||||
export class TextEditingComponent implements OnInit, OnDestroy {
|
|
||||||
textEditingFinished: Subscription;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private textEditingTool: TextEditingTool,
|
|
||||||
private drawingEventSource: DrawingsEventSource
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.textEditingFinished = this.textEditingTool.editingFinished.subscribe((evt: TextEditedDataEvent) => {
|
|
||||||
this.drawingEventSource.textEdited.emit(evt);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.textEditingFinished.unsubscribe();
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,7 +5,6 @@ import { DrawingsWidget } from './widgets/drawings';
|
|||||||
import { DrawingLineWidget } from './widgets/drawing-line';
|
import { DrawingLineWidget } from './widgets/drawing-line';
|
||||||
import { SelectionTool } from './tools/selection-tool';
|
import { SelectionTool } from './tools/selection-tool';
|
||||||
import { MovingTool } from './tools/moving-tool';
|
import { MovingTool } from './tools/moving-tool';
|
||||||
import {TextEditingTool} from './tools/text-editing-tool';
|
|
||||||
import { LayersWidget } from './widgets/layers';
|
import { LayersWidget } from './widgets/layers';
|
||||||
import { LinkWidget } from './widgets/link';
|
import { LinkWidget } from './widgets/link';
|
||||||
import { InterfaceStatusWidget } from './widgets/interface-status';
|
import { InterfaceStatusWidget } from './widgets/interface-status';
|
||||||
@ -29,7 +28,6 @@ export const D3_MAP_IMPORTS = [
|
|||||||
DrawingLineWidget,
|
DrawingLineWidget,
|
||||||
SelectionTool,
|
SelectionTool,
|
||||||
MovingTool,
|
MovingTool,
|
||||||
TextEditingTool,
|
|
||||||
LayersWidget,
|
LayersWidget,
|
||||||
LinkWidget,
|
LinkWidget,
|
||||||
InterfaceStatusWidget,
|
InterfaceStatusWidget,
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
import { Injectable, EventEmitter } from "@angular/core";
|
|
||||||
import { SVGSelection } from '../models/types';
|
|
||||||
import { select } from 'd3-selection';
|
|
||||||
import { TextElement } from '../models/drawings/text-element';
|
|
||||||
import { TextEditedDataEvent } from '../events/event-source';
|
|
||||||
import { DrawingsEventSource } from '../events/drawings-event-source';
|
|
||||||
import { Context } from '../models/context';
|
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class TextEditingTool {
|
|
||||||
private enabled = true;
|
|
||||||
private editingDrawingId: string;
|
|
||||||
private editedElement: any;
|
|
||||||
private temporaryElement: HTMLDivElement;
|
|
||||||
public editingFinished = new EventEmitter<any>();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private drawingEventSource: DrawingsEventSource,
|
|
||||||
private context: Context
|
|
||||||
){}
|
|
||||||
|
|
||||||
public setEnabled(enabled) {
|
|
||||||
this.enabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public draw(selection: SVGSelection){
|
|
||||||
if (!this.enabled){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("From service", selection.selectAll<SVGTextElement, TextElement>('text.text_element'));
|
|
||||||
|
|
||||||
selection.selectAll<SVGTextElement, TextElement>('text.text_element')
|
|
||||||
.on("dblclick", (elem, index, textElements) => {
|
|
||||||
this.editedElement = elem;
|
|
||||||
|
|
||||||
select(textElements[index])
|
|
||||||
.attr("visibility", "hidden");
|
|
||||||
|
|
||||||
select(textElements[index])
|
|
||||||
.classed("editingMode", true);
|
|
||||||
|
|
||||||
this.editingDrawingId = textElements[index].parentElement.parentElement.getAttribute("drawing_id");
|
|
||||||
|
|
||||||
var transformData = textElements[index].parentElement.getAttribute("transform").split(/\(|\)/);
|
|
||||||
var x = Number(transformData[1].split(/,/)[0]) + this.context.getZeroZeroTransformationPoint().x;
|
|
||||||
var y = Number(transformData[1].split(/,/)[1]) + this.context.getZeroZeroTransformationPoint().y;
|
|
||||||
|
|
||||||
this.temporaryElement = document.createElement('div');
|
|
||||||
this.temporaryElement.className = "temporaryElement";
|
|
||||||
this.temporaryElement.style.paddingLeft = "4px";
|
|
||||||
this.temporaryElement.style.width = "fit-content";
|
|
||||||
this.temporaryElement.style.left = x.toString() + 'px';
|
|
||||||
this.temporaryElement.style.top = y.toString() + 'px';
|
|
||||||
this.temporaryElement.style.position = "absolute";
|
|
||||||
this.temporaryElement.style.zIndex = "99";
|
|
||||||
this.temporaryElement.style.fontFamily = elem.font_family;
|
|
||||||
this.temporaryElement.style.fontSize = `${elem.font_size}pt`;
|
|
||||||
this.temporaryElement.style.fontWeight = elem.font_weight;
|
|
||||||
this.temporaryElement.style.color = elem.fill;
|
|
||||||
this.temporaryElement.style.textDecoration = elem.text_decoration;
|
|
||||||
this.temporaryElement.setAttribute("contenteditable", "true");
|
|
||||||
this.temporaryElement.innerText = elem.text;
|
|
||||||
|
|
||||||
this.temporaryElement.addEventListener("focusout", () => {
|
|
||||||
let innerText = this.temporaryElement.innerText;
|
|
||||||
this.editingFinished.emit(new TextEditedDataEvent(this.editingDrawingId, innerText.replace(/\n$/, ""), this.editedElement));
|
|
||||||
|
|
||||||
this.drawingEventSource.textSaved.subscribe((evt:boolean) => {
|
|
||||||
if(evt){
|
|
||||||
this.temporaryElement.remove();
|
|
||||||
document.body.style.cursor = "default";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
selection.selectAll<SVGTextElement, TextElement>('text.editingMode')
|
|
||||||
.attr("visibility", "visible")
|
|
||||||
.classed("editingMode", false);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.body.appendChild(this.temporaryElement);
|
|
||||||
this.temporaryElement.focus();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,7 +8,6 @@ import { MovingTool } from "../tools/moving-tool";
|
|||||||
import { LayersWidget } from "./layers";
|
import { LayersWidget } from "./layers";
|
||||||
import { LayersManager } from "../managers/layers-manager";
|
import { LayersManager } from "../managers/layers-manager";
|
||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from "@angular/core";
|
||||||
import { TextEditingTool } from '../tools/text-editing-tool';
|
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -18,7 +17,6 @@ export class GraphLayout implements Widget {
|
|||||||
private drawingLineTool: DrawingLineWidget,
|
private drawingLineTool: DrawingLineWidget,
|
||||||
private selectionTool: SelectionTool,
|
private selectionTool: SelectionTool,
|
||||||
private movingTool: MovingTool,
|
private movingTool: MovingTool,
|
||||||
private textEditingTool: TextEditingTool,
|
|
||||||
private layersWidget: LayersWidget,
|
private layersWidget: LayersWidget,
|
||||||
private layersManager: LayersManager
|
private layersManager: LayersManager
|
||||||
) {
|
) {
|
||||||
@ -69,7 +67,6 @@ export class GraphLayout implements Widget {
|
|||||||
this.drawingLineTool.draw(view, context);
|
this.drawingLineTool.draw(view, context);
|
||||||
this.selectionTool.draw(view, context);
|
this.selectionTool.draw(view, context);
|
||||||
this.movingTool.draw(view, context);
|
this.movingTool.draw(view, context);
|
||||||
this.textEditingTool.draw(view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnect(view: SVGSelection) {
|
disconnect(view: SVGSelection) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user