UNPKG

devexpress-diagram

Version:

DevExpress Diagram Control

240 lines (220 loc) 11.3 kB
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; } }