UNPKG

devexpress-diagram

Version:

DevExpress Diagram Control

166 lines (156 loc) 8.83 kB
import { ToolboxDraggingObject, IShapeToolboxOptions, Toolbox } from "./Toolbox"; import { IShapeDescriptionManager } from "../../Model/Shapes/Descriptions/ShapeDescriptionManager"; import { svgNS } from "../RenderHelper"; import { Shape } from "../../Model/Shapes/Shape"; import { ShapeDescription } from "../../Model/Shapes/Descriptions/ShapeDescription"; import { UnitConverter } from "@devexpress/utils/lib/class/unit-converter"; import { Point } from "@devexpress/utils/lib/geometry/point"; import { TextShapeDescription } from "../../Model/Shapes/Descriptions/General/TextShapeDescription"; import { ITextMeasurer } from "../Measurer/ITextMeasurer"; import { DEFAULT_STROKE_WIDTH } from "../../Model/Style"; import { CustomShapeDescription } from "../../Model/Shapes/Descriptions/CustomShapeDescription"; import { RectanglePrimitive } from "../Primitives/RectaglePrimitive"; const DEFAULT_SHAPE_ICON_SIZE = 32; const SHRINK_TEXT_SHAPE_ICON_SIZE = 26; const SHRINKED_TEXT = "T"; export class IconToolbox extends Toolbox { options: IShapeIconToolboxOptions; instanceId: string; constructor(parent: HTMLElement, readonly: boolean, allowDragging: boolean, shapeDescriptionManager: IShapeDescriptionManager, shapeTypes: string[], getAllowedShapeTypes: (shapes: string[]) => string[], options: IShapeIconToolboxOptions, measurer: ITextMeasurer, instanceId: string) { super(parent, readonly, allowDragging, shapeDescriptionManager, shapeTypes, getAllowedShapeTypes); this.options = options; this.measurer = measurer; this.instanceId = instanceId; } createElements(element: HTMLElement, shapeTypes: string[]) { const svgElement = document.createElementNS(svgNS, "svg"); svgElement.className.baseVal = "dxdi-canvas"; element.appendChild(svgElement); this.drawShapeIcons(svgElement, shapeTypes, this.options.toolboxWidth || svgElement.getBoundingClientRect().width); } drawShapeIcons(parent: SVGElement, shapeTypes: string[], svgWidth: number) { const lineWidth = DEFAULT_STROKE_WIDTH; const targetWidth = svgWidth - 2 * lineWidth; let shapeIconSize = this.options.shapeIconSize; if(!shapeIconSize && this.options.shapeIconSpacing && this.options.shapeIconCountInRow) shapeIconSize = Math.floor((targetWidth - (this.options.shapeIconCountInRow - 1) * this.options.shapeIconSpacing) / this.options.shapeIconCountInRow); if(!shapeIconSize) shapeIconSize = DEFAULT_SHAPE_ICON_SIZE; shapeIconSize = Math.max(shapeIconSize, this.options.shapeIconSpacing / 2); let width = shapeIconSize; let iconCountInRow = this.options.shapeIconCountInRow; if(!iconCountInRow) { iconCountInRow = 1; while(width < targetWidth) { width += this.options.shapeIconSpacing + shapeIconSize; if(width < targetWidth) iconCountInRow++; } } const shapeIconSpacing = (iconCountInRow > 1) ? (targetWidth - shapeIconSize * iconCountInRow) / (iconCountInRow - 1) : 0; let xPos = lineWidth; let yPos = lineWidth; const size = UnitConverter.pixelsToTwips(shapeIconSize); shapeTypes.forEach((shapeType, index) => { if(index > 0 && index % iconCountInRow === 0) { xPos = lineWidth; yPos += shapeIconSize + shapeIconSpacing; } const shapeDescription = this.shapeDescriptionManager.get(shapeType); const shape = this.createShape(shapeDescription, xPos, yPos, shapeIconSize < SHRINK_TEXT_SHAPE_ICON_SIZE); this.updateShapeIconBounds(shape, shapeIconSize); const shapeEl = this.drawShape(parent, shape); this.drawSelector(shapeEl, UnitConverter.pixelsToTwips(xPos), UnitConverter.pixelsToTwips(yPos), size); xPos += shapeIconSize + shapeIconSpacing; }); parent.style.height = yPos + shapeIconSize + lineWidth + "px"; parent.style.width = svgWidth + "px"; } drawShape(parent: SVGElement, shape: Shape): SVGGElement { const primitives = shape.description.createPrimitives(shape, this.instanceId, true); const gEl: SVGGElement = document.createElementNS(svgNS, "g"); gEl.setAttribute("data-tb-type", shape.description.key.toString()); gEl.setAttribute("class", "toolbox-item"); gEl.setAttribute("title", shape.description.getTitle()); if(this.options.shapeIconAttributes) for(const key in this.options.shapeIconAttributes) if(Object.prototype.hasOwnProperty.call(this.options.shapeIconAttributes, key)) gEl.setAttribute(key, this.options.shapeIconAttributes[key]); parent.appendChild(gEl); primitives.forEach(pr => { const el = pr.createElement(e => gEl.appendChild(e)); pr.applyElementProperties(el, this.measurer); }); return gEl; } drawSelector(parent: SVGGElement, x: number, y: number, size: number) { const selectorRect = new RectanglePrimitive(x, y, size, size, undefined, "selector"); selectorRect.createElement(el => { selectorRect.applyElementProperties(el, this.measurer); parent.appendChild(el); }); } createShape(shapeDescription: ShapeDescription, xPos: number, yPos: number, shrinkText?: boolean) { const xPosT = UnitConverter.pixelsToTwips(xPos); const yPosT = UnitConverter.pixelsToTwips(yPos); const shape = new Shape(shapeDescription, new Point(xPosT, yPosT), true); if(this.needResetShapeText(shapeDescription)) shape.text = ""; else if(shrinkText) shape.text = SHRINKED_TEXT; return shape; } needResetShapeText(shapeDescription: ShapeDescription) { if(shapeDescription instanceof TextShapeDescription) return false; if(shapeDescription instanceof CustomShapeDescription && shapeDescription.baseDescription instanceof TextShapeDescription) return false; return true; } updateShapeIconBounds(shape: Shape, shapeIconSize: number) { const shapeSizeT = UnitConverter.pixelsToTwips(shapeIconSize); shape.size.height = shape.size.width * shape.getToolboxHeightToWidthRatio(); if(shape.size.width > shape.size.height) { const ratio = shape.size.height / shape.size.width; shape.size.width = shapeSizeT; shape.size.height = shapeSizeT * ratio; shape.position.y = shape.position.y + (shapeSizeT - shape.size.height) / 2; shape.parameters.forEach((p) => { p.value = p.value * shapeSizeT / shape.description.defaultSize.width; }); } else if(shape.size.width < shape.size.height) { const ratio = shape.size.width / shape.size.height; shape.size.height = shapeSizeT; shape.size.width = shapeSizeT * ratio; shape.position.x = shape.position.x + (shapeSizeT - shape.size.width) / 2; shape.parameters.forEach((p) => { p.value = p.value * shapeSizeT / shape.description.defaultSize.height; }); } else { shape.size.width = shapeSizeT; shape.size.height = shapeSizeT; shape.parameters.forEach((p) => { p.value = p.value * shapeSizeT / shape.description.defaultSize.width; }); } } protected createDraggingElement(draggingObject: ToolboxDraggingObject): HTMLElement { const element = document.createElement("DIV"); element.setAttribute("class", "dxdi-toolbox-drag-item"); document.body.appendChild(element); const svgElement = document.createElementNS(svgNS, "svg"); svgElement.className.baseVal = "dxdi-canvas"; element.appendChild(svgElement); const shapeDescription = this.shapeDescriptionManager.get(draggingObject.evt.data); const shape = this.createShape(shapeDescription, DEFAULT_STROKE_WIDTH, DEFAULT_STROKE_WIDTH); this.drawShape(svgElement, shape); element.style.width = UnitConverter.twipsToPixels(shape.size.width) + 2 * DEFAULT_STROKE_WIDTH + "px"; element.style.height = UnitConverter.twipsToPixels(shape.size.height) + 2 * DEFAULT_STROKE_WIDTH + "px"; return element; } } export interface IShapeIconToolboxOptions extends IShapeToolboxOptions { shapeIconSpacing: number; shapeIconSize?: number; shapeIconCountInRow?: number; shapeIconAttributes?: {[key: string]: any}; toolboxWidth?: number; }