devexpress-diagram
Version:
DevExpress Diagram Control
240 lines (220 loc) • 11.3 kB
text/typescript
import { DiagramModel } from "../Model/Model";
import { Connector } from "../Model/Connectors/Connector";
import { Shape } from "../Model/Shapes/Shape";
import { ImporterBase } from "./ImporterBase";
import { ShapeTypes } from "../Model/Shapes/ShapeTypes";
import { ShapeDescriptionManager } from "../Model/Shapes/Descriptions/ShapeDescriptionManager";
import { Size } from "@devexpress/utils/lib/geometry/size";
import { Point } from "@devexpress/utils/lib/geometry/point";
import { ImportUtils } from "./ImportUtils";
import { DiagramItem } from "../Model/DiagramItem";
import { ColorUtils } from "@devexpress/utils/lib/utils/color";
import { UnitConverter } from "@devexpress/utils/lib/class/unit-converter";
export class XmlImporter extends ImporterBase {
protected doc: Document;
protected static readonly shapeTypes: {[key: string]: string} = {
"BasicShapes.Rectangle": ShapeTypes.Rectangle,
"BasicShapes.Ellipse": ShapeTypes.Ellipse,
"BasicShapes.Triangle": ShapeTypes.Triangle,
"BasicShapes.Pentagon": ShapeTypes.Pentagon,
"BasicShapes.Hexagon": ShapeTypes.Hexagon,
"BasicShapes.Octagon": ShapeTypes.Octagon,
"BasicShapes.Diamond": ShapeTypes.Diamond,
"BasicShapes.Cross": ShapeTypes.Cross,
"BasicShapes.Star5": ShapeTypes.Star,
"BasicFlowchartShapes.StartEnd": ShapeTypes.Terminator,
"BasicFlowchartShapes.Data": ShapeTypes.Data,
"BasicFlowchartShapes.Database": ShapeTypes.Database,
"BasicFlowchartShapes.ExternalData": ShapeTypes.StoredData,
"BasicFlowchartShapes.Process": ShapeTypes.Process,
"BasicFlowchartShapes.Decision": ShapeTypes.Decision,
"BasicFlowchartShapes.Subprocess": ShapeTypes.PredefinedProcess,
"BasicFlowchartShapes.Document": ShapeTypes.Document,
"BasicFlowchartShapes.Custom1": ShapeTypes.ManualInput,
"BasicFlowchartShapes.Custom2": ShapeTypes.ManualOperation,
"ArrowShapes.SimpleArrow": ShapeTypes.ArrowLeft,
"ArrowShapes.SimpleDoubleArrow": ShapeTypes.ArrowLeftRight
};
constructor(shapeDescriptionManager: ShapeDescriptionManager, xml: string) {
super(shapeDescriptionManager);
this.doc = ImportUtils.createDocument(xml);
}
getObject(): any {
return this.doc;
}
getPageObject(obj: any): any {
const pageElements = this.doc.querySelectorAll("[ItemKind='DiagramRoot']");
return pageElements && pageElements[0];
}
getShapeObjects(obj: any): any[] {
const shapeObjs = [];
this.doc.querySelectorAll("[ItemKind='DiagramRoot'] > Children > [ItemKind='DiagramShape']").forEach(obj => { shapeObjs.push(obj); });
this.doc.querySelectorAll("[ItemKind='DiagramRoot'] > Children > [ItemKind='DiagramContainer']").forEach(obj => { shapeObjs.push(obj); });
return shapeObjs;
}
getConnectorObjects(obj: any): any[] {
const connectorObjs = [];
this.doc.querySelectorAll("[ItemKind='DiagramRoot'] > Children > [ItemKind='DiagramConnector']").forEach(obj => { connectorObjs.push(obj); });
return connectorObjs;
}
importPageSettings(model: DiagramModel, pageObj: Element) {
if(!pageObj) return;
const pageSizeAttr = pageObj.getAttribute("PageSize");
const pageSize = this.getSize(pageSizeAttr);
if(pageSize) {
model.size = pageSize.clone();
model.pageSize = pageSize.clone();
}
}
importShape(shapeObj: Element): Shape {
const positionAttr = shapeObj.getAttribute("Position");
const position = this.getPoint(positionAttr);
const shapeAttr = shapeObj.getAttribute("Shape");
const shapeType = this.getShapeType(shapeAttr);
const description = this.shapeDescriptionManager.get(shapeType);
const shape = new Shape(description || ShapeDescriptionManager.default, position);
shape.key = this.getItemKey(shapeObj);
const sizeAttr = shapeObj.getAttribute("Size");
const size = this.getSize(sizeAttr);
if(size) shape.size = size;
const contentAttr = shapeObj.getAttribute("Content");
if(typeof contentAttr === "string")
shape.text = contentAttr;
else {
const headerAttr = shapeObj.getAttribute("Header");
if(typeof headerAttr === "string")
shape.text = headerAttr;
}
this.importStyle(shapeObj, shape);
return shape;
}
importShapeChildren(shapeObj: Element, shape: Shape): Shape[] {
const childShapeObjs = [];
shapeObj.setAttribute("dxDiagram", "");
this.doc.querySelectorAll("[dxDiagram] > Children > [ItemKind='DiagramShape']").forEach(obj => { childShapeObjs.push(obj); });
this.doc.querySelectorAll("[dxDiagram] > Children > [ItemKind='DiagramContainer']").forEach(obj => { childShapeObjs.push(obj); });
shapeObj.removeAttribute("dxDiagram");
let result = [];
if(!childShapeObjs) return result;
for(let i = 0; i < childShapeObjs.length; i++) {
const childShapeObj = childShapeObjs[i];
const childShape = this.importShape(childShapeObj);
childShape.key = shape.key + "," + childShape.key;
const rect = shape.clientRectangle;
childShape.position = childShape.position.clone().offset(rect.x, rect.y);
if(!shape["childKeys"])
shape["childKeys"] = [];
shape["childKeys"].push(childShape.key);
result.push(childShape);
result = result.concat(this.importShapeChildren(childShapeObj, childShape));
}
return result;
}
importConnector(connectorObj: Element): Connector {
const points = [];
const beginPointAttr = connectorObj.getAttribute("BeginPoint");
const beginPoint = this.getPoint(beginPointAttr);
if(beginPoint) points.push(beginPoint);
const pointsAttr = connectorObj.getAttribute("Points");
pointsAttr.split(" ").forEach(pointAttr => {
const point = this.getPoint(pointAttr);
if(point) points.push(point);
});
const endPointAttr = connectorObj.getAttribute("EndPoint");
const endPoint = this.getPoint(endPointAttr);
if(endPoint) points.push(endPoint);
const connector = new Connector(points);
connector.key = this.getItemKey(connectorObj);
const endItemPointIndexAttr = connectorObj.getAttribute("EndItemPointIndex");
const endItemPointIndex = parseInt(endItemPointIndexAttr);
connector.endConnectionPointIndex = !isNaN(endItemPointIndex) ? endItemPointIndex : -1;
const beginItemPointIndexAttr = connectorObj.getAttribute("BeginItemPointIndex");
const beginItemPointIndex = parseInt(beginItemPointIndexAttr);
connector.beginConnectionPointIndex = !isNaN(beginItemPointIndex) ? beginItemPointIndex : -1;
const endItemAttr = connectorObj.getAttribute("EndItem");
if(endItemAttr !== undefined)
this.assert(endItemAttr, "string");
const beginItemAttr = connectorObj.getAttribute("BeginItem");
if(beginItemAttr !== undefined)
this.assert(beginItemAttr, "string");
connector["endItemKey"] = endItemAttr;
connector["beginItemKey"] = beginItemAttr;
const contentAttr = connectorObj.getAttribute("Content");
if(typeof contentAttr === "string")
connector.setText(contentAttr);
this.importStyle(connectorObj, connector);
return connector;
}
importStyle(obj: Element, item: DiagramItem) {
const backgroundAttr = obj.getAttribute("Background");
if(typeof backgroundAttr === "string")
item.style["fill"] = this.getColor(backgroundAttr);
const strokeAttr = obj.getAttribute("Stroke");
if(typeof strokeAttr === "string")
item.style["stroke"] = this.getColor(strokeAttr);
const foregroundAttr = obj.getAttribute("Foreground");
if(typeof foregroundAttr === "string")
item.styleText["fill"] = this.getColor(foregroundAttr);
const fontFamilyAttr = obj.getAttribute("FontFamily");
if(typeof fontFamilyAttr === "string")
item.styleText["font-family"] = fontFamilyAttr;
const fontSizeAttr = obj.getAttribute("FontSize");
if(typeof fontSizeAttr === "string")
item.styleText["font-size"] = fontSizeAttr;
const fontWeightAttr = obj.getAttribute("FontWeight");
if(fontWeightAttr === "Bold")
item.styleText["font-weight"] = "bold";
const fontStyleAttr = obj.getAttribute("FontStyle");
if(fontStyleAttr === "Italic")
item.styleText["font-style"] = "italic";
const textDecorationsAttr = obj.getAttribute("TextDecorations");
if(textDecorationsAttr === "Underline")
item.styleText["text-decoration"] = "underline";
const textAlignmentAttr = obj.getAttribute("TextAlignment");
if(textAlignmentAttr === "Left")
item.styleText["text-anchor"] = "start";
else if(textAlignmentAttr === "Right")
item.styleText["text-anchor"] = "end";
else if(textAlignmentAttr === "Center")
item.styleText["text-anchor"] = "middle";
}
private getShapeType(shapeAttr: string) {
if(XmlImporter.shapeTypes[shapeAttr])
return XmlImporter.shapeTypes[shapeAttr];
if(shapeAttr && shapeAttr.toLowerCase().indexOf("container") > -1)
return ShapeTypes.VerticalContainer;
return ShapeTypes.Rectangle;
}
private getItemKey(obj: Element) {
return (parseInt(obj.tagName.replace("Item", "")) - 1).toString();
}
private getNumbers(s: string): number[] {
const parts = s.split(",");
return parts && parts.length ? parts.map(part => +part) : [];
}
private getSize(attrValue: string): Size {
if(attrValue) {
const numbers = this.getNumbers(attrValue);
if(numbers.length >= 2) {
this.assert(numbers[0], "number");
this.assert(numbers[1], "number");
return new Size(UnitConverter.pixelsToTwips(numbers[0]), UnitConverter.pixelsToTwips(numbers[1]));
}
}
}
private getPoint(attrValue: string): Point {
if(attrValue) {
const numbers = this.getNumbers(attrValue);
if(numbers.length >= 2) {
this.assert(numbers[0], "number");
this.assert(numbers[1], "number");
return new Point(UnitConverter.pixelsToTwips(numbers[0]), UnitConverter.pixelsToTwips(numbers[1]));
}
}
}
private getColor(attrValue: string): string {
attrValue = attrValue.charAt(0) === "#" ? attrValue.substr(1) : attrValue;
const color = parseInt(attrValue, 16);
return !isNaN(color) ? ColorUtils.colorToHash(color) : undefined;
}
}