Reimplementation of text editing

This commit is contained in:
Piotr Pekala 2018-12-12 06:55:22 -08:00
parent 92d6c8e411
commit f0582e6a9e
5 changed files with 86 additions and 66 deletions

View File

@ -9,4 +9,5 @@ export class DrawingsEventSource {
public resized = new EventEmitter<ResizedDataEvent<MapDrawing>>();
public textAdded = new EventEmitter<TextAddedDataEvent>();
public textEdited = new EventEmitter<TextEditedDataEvent>();
public textSaved = new EventEmitter<any>();
}

View File

@ -1,15 +1,19 @@
import { Injectable, EventEmitter } from "@angular/core";
import { TextAddedDataEvent } from '../events/event-source';
import { DrawingsEventSource } from '../events/drawings-event-source';
@Injectable()
export class TextAddingTool {
private enabled;
private listener: Function;
private temporaryElement: HTMLDivElement;
public addingFinished = new EventEmitter<any>();
constructor(
private drawingEventSource: DrawingsEventSource
){}
public setEnabled(enabled){
this.enabled = enabled;
if (enabled){
this.activate();
} else {
@ -26,37 +30,43 @@ export class TextAddingTool {
var map = document.getElementsByClassName('map')[0];
let addTextListener = (event: MouseEvent) => {
var div = document.createElement('div');
div.style.width = "fit-content";
div.style.left = event.clientX.toString() + 'px';
div.style.top = (event.clientY).toString() + 'px';
div.style.position = "absolute";
div.style.zIndex = "99";
div.style.fontFamily = "Noto Sans";
div.style.fontSize = "11pt";
div.style.fontWeight = "bold";
div.style.color = "#000000";
div.setAttribute("contenteditable", "true");
document.body.appendChild(div);
div.innerText = "";
div.focus();
this.temporaryElement = this.getTemporaryElement(event.clientX, event.clientY);
document.body.appendChild(this.temporaryElement);
this.temporaryElement.focus();
document.body.style.cursor = "text";
div.addEventListener("focusout", () => {
let savedText = div.innerText;
this.temporaryElement.addEventListener("focusout", () => {
let savedText = this.temporaryElement.innerText;
this.addingFinished.emit(new TextAddedDataEvent(savedText, event.clientX, event.clientY));
document.body.style.cursor = "default";
div.remove();
this.drawingEventSource.textSaved.subscribe((evt:boolean) => {
if(evt){
this.temporaryElement.remove();
document.body.style.cursor = "default";
}
});
});
}
map.removeEventListener('click', this.listener as EventListenerOrEventListenerObject);
this.listener = addTextListener;
map.addEventListener('click', this.listener as EventListenerOrEventListenerObject, {once : true});
}
}
private getTemporaryElement(x:number, y:number): HTMLDivElement{
var elem = document.createElement('div');
elem.style.width = "fit-content";
elem.style.left = x.toString() + 'px';
elem.style.top = y.toString() + 'px';
elem.style.position = "absolute";
elem.style.zIndex = "99";
elem.style.fontFamily = "Noto Sans";
elem.style.fontSize = "11pt";
elem.style.fontWeight = "bold";
elem.style.color = "#000000";
elem.setAttribute("contenteditable", "true");
elem.innerText = "";
return elem;
}
}

View File

@ -3,6 +3,7 @@ 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';
@Injectable()
@ -10,8 +11,13 @@ export class TextEditingTool {
private enabled = true;
private editingDrawingId: string;
private editedElement: any;
private temporaryElement: HTMLDivElement;
public editingFinished = new EventEmitter<any>();
constructor(
private drawingEventSource: DrawingsEventSource
){}
public setEnabled(enabled) {
this.enabled = enabled;
}
@ -34,45 +40,44 @@ export class TextEditingTool {
this.editingDrawingId = textElements[index].parentElement.parentElement.getAttribute("drawing_id");
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:span")
.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", () => {
let temporaryText = document.getElementsByClassName("temporaryTextInside")[0] as HTMLElement;
let savedText = temporaryText.innerText;
this.editingFinished.emit(new TextEditedDataEvent(this.editingDrawingId, savedText, this.editedElement));
var splitted = textElements[index].parentElement.getAttribute("transform").split(/\(|\)/);
var x = Number(splitted[1].split(/,/)[0]);
var y = Number(splitted[1].split(/,/)[1]);
console.log(x);
console.log(y);
var temporaryElement = document.getElementById("temporaryText") as HTMLElement;
temporaryElement.remove();
this.temporaryElement = document.createElement('div');
this.temporaryElement.style.width = "fit-content";
this.temporaryElement.style.left = '100px';//x.toString() + 'px';
this.temporaryElement.style.top = '100px';//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;
selection.selectAll<SVGTextElement, TextElement>('text.editingMode')
.attr("visibility", "visible")
.classed("editingMode", false);
this.temporaryElement.addEventListener("focusout", () => {
let savedText = this.temporaryElement.innerText;
this.editingFinished.emit(new TextEditedDataEvent(this.editingDrawingId, savedText, this.editedElement));
this.drawingEventSource.textSaved.subscribe((evt:boolean) => {
if(evt){
this.temporaryElement.remove();
document.body.style.cursor = "default";
}
});
var txtInside = document.getElementsByClassName("temporaryTextInside")[0] as HTMLElement;
txtInside.focus();
selection.selectAll<SVGTextElement, TextElement>('text.editingMode')
.attr("visibility", "visible")
.classed("editingMode", false);
});
document.body.appendChild(this.temporaryElement);
this.temporaryElement.focus();
});
}
}

View File

@ -356,7 +356,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
});
}
public onTextAdded(evt: TextAddedDataEvent){
public onTextAdded(evt: TextAddedDataEvent) {
this.resetDrawToolChoice();
let drawing = this.getDrawingMock("text", evt.savedText);
@ -368,10 +368,11 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
.subscribe((serverDrawing: Drawing) => {
document.body.style.cursor = "default";
this.drawingsDataSource.add(serverDrawing);
this.drawingsEventSource.textSaved.emit(true);
});
}
public onTextEdited(evt: TextEditedDataEvent){
public onTextEdited(evt: TextEditedDataEvent) {
let mapDrawing: MapDrawing = new MapDrawing();
mapDrawing.element = evt.textElement;
(mapDrawing.element as TextElement).text = evt.editedText;
@ -383,6 +384,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
.updateText(this.server, drawing, svgString)
.subscribe((serverDrawing: Drawing) => {
this.drawingsDataSource.update(serverDrawing);
this.drawingsEventSource.textSaved.emit(true);
});
}
@ -465,7 +467,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
map.addEventListener('click', this.drawListener as EventListenerOrEventListenerObject, {once : true});
}
public resetDrawToolChoice(){
public resetDrawToolChoice() {
this.drawTools.isRectangleChosen = false;
this.drawTools.isEllipseChosen = false;
this.drawTools.isLineChosen = false;
@ -473,14 +475,14 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
this.selectedDrawing = "";
}
public hideMenu(){
public hideMenu() {
var map = document.getElementsByClassName('map')[0];
map.removeEventListener('click', this.drawListener as EventListenerOrEventListenerObject);
this.resetDrawToolChoice();
this.drawTools.visibility = false;
}
public showMenu(){
public showMenu() {
setTimeout(() => {
this.drawTools.visibility = true;
},
@ -546,10 +548,12 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
return mapDrawing;
}
public addText(){
public addText() {
if (!this.drawTools.isAddingTextChosen){
this.resetDrawToolChoice();
this.drawTools.isAddingTextChosen = true;
var map = document.getElementsByClassName('map')[0];
map.removeEventListener('click', this.drawListener as EventListenerOrEventListenerObject);
} else {
this.resetDrawToolChoice();
}