import { ZVertex } from "./z_vertex" import { ZTextBox } from "./z_textbox" import { ZCalloutAttributes } from "./z_callout" import { ShapeObjectType, ConnectorType, msoDashStyle, VBAShapeType, DataName } from "../common/enums"; import * as AttributeNames from "../common/attribute_names" import * as StyleNames from "../common/style_names" import { Rectangle, VLine, round100 } from "../common/vline" import * as CSS from "../html/css" import * as GOptions from "./z_options" import { updateAppropriateDashArray } from "../html/enum_extension"; import * as ElementExtension from "../interfaces/element_extension" import * as DefaultClassNames from "../common/default_class_names" /** * ZRectです。 * */ export class ZRect extends ZTextBox { public get svgRectangle(): SVGRectElement { return this._svgSurface; } public constructor(svgbox: SVGElement | string, option : GOptions.ZTextBoxAttributes | null = null) { super(svgbox); this.updateAttributes.push("width"); this.updateAttributes.push("height"); //throw Error("error2"); //this.update(); if (this.type == ShapeObjectType.Rect) this.firstFunctionAfterInitialized(); } protected createSurface(svgbox: SVGElement): void { this._svgSurface = ZRect.createRectangle(this.svgGroup, DefaultClassNames.defaultSurfaceClass, undefined); this.svgGroup.insertBefore(this.svgRectangle, this.svgText); } /** * SVGRectElementを生成します。 * @param parent 生成したSVG要素を子に追加する要素 * @param className 生成するSVG要素のクラス属性名 * @returns 生成されたSVGRectElement */ private static createRectangle(parent: SVGElement, className: string | GOptions.surfaceClassCSS | undefined, style: string | undefined | GOptions.surfaceClassCSS): SVGRectElement { const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); rect.setAttribute(AttributeNames.dataNameAttribute, DataName.Surface); parent.appendChild(rect); rect.width.baseVal.value = 30; rect.height.baseVal.value = 30; if (style !== undefined) { if (typeof (style) == "string") { rect.setAttribute("style", style); } else { rect.setAttribute("style", CSS.buildClassNameFromSurfaceClassCSS(style)); } } //if(style !== undefined) rect.setAttribute("style", style); if (className == null) { if (rect.style.stroke == null || rect.style.stroke == "") rect.style.stroke = "black"; if (rect.style.fill == null || rect.style.fill == "") rect.style.fill = "white"; if (rect.style.strokeWidth == null || rect.style.strokeWidth == "") rect.style.strokeWidth = "1pt"; } else { if (typeof (className) == "string") { rect.setAttribute("class", className); } else { rect.setAttribute("class", CSS.buildClassNameFromSurfaceClassCSS(className)); } //const dashStyle = rect.getPropertyStyleValue(GraphTableSVG.AttributeNames.Style.msoDashStyleName); //if (dashStyle != null) msoDashStyle.setStyle(rect, dashStyle); const width = ElementExtension.getPropertyStyleNumberValue(rect, StyleNames.defaultWidth, null); if (width != null) { rect.width.baseVal.value = width; } const height = ElementExtension.getPropertyStyleNumberValue(rect, StyleNames.defaultHeight, null); if (height != null) { rect.height.baseVal.value = height; } } return rect; } /* static constructAttributes(e: Element, removeAttributes: boolean = false, output: GOptions.ZTextBoxAttributes = {}): GOptions.ZTextBoxAttributes { ZTextBox.constructAttributes(e, removeAttributes, output); return output; } */ public get type(): ShapeObjectType { return ShapeObjectType.Rect; } /* get innerRectangle(): Rectangle { const rect = new Rectangle(); rect.width = this.width; rect.height = this.height; rect.x = (-this.width / 2); rect.y = (-this.height / 2); return rect; } */ /** 頂点の幅を返します。 */ get width(): number { return round100(this.svgRectangle.width.baseVal.value); } set width(value: number) { //const value100 = round100(value); //if (this.width != value100) this.svgRectangle.setAttribute("width", value100.toString()); this.setWidthWithoutUpdate(value); //this.update(); } protected setWidthWithoutUpdate(value: number) { const value100 = round100(value); if (this.width != value100) { this.svgRectangle.setAttribute("width", value100.toString()); } } /** 頂点の高さを返します。 */ get height(): number { return round100(this.svgRectangle.height.baseVal.value); } set height(value: number) { this.setHeightWithoutUpdate(value); //this.update(); } protected setHeightWithoutUpdate(value: number) { const value100 = round100(value); if (this.height != value100) this.svgRectangle.setAttribute("height", value100.toString()); } public get surfaceRegion(): Rectangle { const x = this.svgRectangle.x.baseVal.value; const y = this.svgRectangle.y.baseVal.value; const w = this.width; const h = this.height return new Rectangle(x, y, w, h); } protected updateSurfaceLocation() { const virtualRegion = this.getVirtualRegion(); this.svgRectangle.x.baseVal.value = -virtualRegion.width / 2; this.svgRectangle.y.baseVal.value = -virtualRegion.height / 2; return false; } /* protected updateSurface() { this.hasConnectedObserverFunction = false; const dashStyle = this.msoDashStyle; if (dashStyle != null) { setComputedDashArray(this.svgRectangle); } this.hasConnectedObserverFunction = true; //this._observer.observe(this.svgGroup, this._observerOption); } */ /** * 接続部分の座標を返します。 * @param type * @param x * @param y */ public getContactPosition(type: ConnectorType, x: number, y: number): [number, number] { const wr = this.width / 2; const hr = this.height / 2; switch (type) { case ConnectorType.Top: return [this.cx, this.cy - hr]; case ConnectorType.TopRight: case ConnectorType.Right: case ConnectorType.BottomRight: return [this.cx + wr, this.cy]; case ConnectorType.Bottom: return [this.cx, this.cy + hr]; case ConnectorType.BottomLeft: case ConnectorType.Left: case ConnectorType.TopLeft: return [this.cx - wr, this.cy]; default: const autoType = this.getContactAutoPosition(x, y); return this.getContactPosition(autoType, x, y); } } public getContactAutoPosition(x: number, y: number): ConnectorType { const wr = this.width / 2; const hr = this.height / 2; const line1 = new VLine(this.cx, this.cy, this.cx + wr, this.cy + hr); const line2 = new VLine(this.cx, this.cy, this.cx + wr, this.cy - hr); const b1 = line1.contains(x, y); const b2 = line2.contains(x, y); if (b1) { if (b2) { return ConnectorType.Top; } else { return ConnectorType.Right; } } else { if (b2) { return ConnectorType.Left; } else { return ConnectorType.Bottom; } } } public get shape(): VBAShapeType { return VBAShapeType.Rectangle; } } //}