devexpress-diagram
Version:
DevExpress Diagram Control
177 lines (157 loc) • 7.16 kB
text/typescript
import { UnitConverter } from "@devexpress/utils/lib/class/unit-converter";
import { Size } from "@devexpress/utils/lib/geometry/size";
import { DiagramLocalizationService } from "../../../LocalizationService";
import { TextOwner } from "../../../Render/Measurer/ITextMeasurer";
import { SvgPrimitive } from "../../../Render/Primitives/Primitive";
import { RectanglePrimitive } from "../../../Render/Primitives/RectaglePrimitive";
import { TextAngle, TextPrimitive } from "../../../Render/Primitives/TextPrimitive";
import { EventDispatcher } from "../../../Utils";
import { Rectangle } from "@devexpress/utils/lib/geometry/rectangle";
import { ConnectionPoint } from "../../ConnectionPoint";
import { ConnectionPointSide, DiagramItem } from "../../DiagramItem";
import { Shape } from "../Shape";
import { ShapeParameterPoint } from "../ShapeParameterPoint";
import { ShapeParameters } from "../ShapeParameters";
import { Point } from "@devexpress/utils/lib/geometry/point";
export const ShapeDefaultDimension = 1440;
export const ShapeMinDimension = 360;
export const ShapeDefaultSize = new Size(ShapeDefaultDimension, ShapeDefaultDimension);
export const ShapeTextPadding = UnitConverter.pixelsToTwips(10);
export abstract class ShapeDescription {
protected connectionPoints: ConnectionPoint[];
protected connectionPointsWhileSelected: ConnectionPoint[];
static readonly textSpacing = UnitConverter.pixelsToTwips(2);
onChanged: EventDispatcher<IShapeDescriptionChangesListener> = new EventDispatcher();
constructor(public defaultSize: Size = ShapeDefaultSize.clone(), protected hasDefaultText?: boolean) {
this.connectionPoints = this.createConnectionPoints();
}
abstract get key(): string;
get enableText() { return true; }
get allowEditText() { return true; }
get enableImage() { return false; }
get allowEditImage() { return true; }
get hasTemplate() { return false; }
get enableChildren() { return false; }
get minWidth() { return undefined; }
get minHeight() { return undefined; }
get maxWidth() { return undefined; }
get maxHeight() { return undefined; }
get toolboxSize() { return this.defaultSize; }
abstract get keepRatioOnAutoSize(): boolean;
getTitle() {
return DiagramLocalizationService.shapeTexts[this.key];
}
getDefaultText() {
return this.hasDefaultText ? DiagramLocalizationService.shapeTexts[this.key] : "";
}
getDefaultImageUrl() {
return "";
}
getConnectionPoints(): ConnectionPoint[] {
return this.connectionPoints;
}
protected createConnectionPoints(): ConnectionPoint[] {
return [
new ConnectionPoint(0.5, 0, ConnectionPointSide.North),
new ConnectionPoint(1, 0.5, ConnectionPointSide.East),
new ConnectionPoint(0.5, 1, ConnectionPointSide.South),
new ConnectionPoint(0, 0.5, ConnectionPointSide.West)
];
}
processConnectionPoint(shape: Shape, point: ConnectionPoint) {
}
getConnectionPointIndexForItem(item: DiagramItem, connectionPointIndex: number): number {
return connectionPointIndex;
}
getConnectionPointIndexForSide(side: ConnectionPointSide): number {
return side;
}
static getConnectionPointSideByGeometry(point: Point): ConnectionPointSide {
if(point.x >= point.y && (point.x > 0 || point.y > 0)) {
if(point.x < 0.5 || (1 - point.x) >= point.y)
return ConnectionPointSide.North;
return ConnectionPointSide.East;
}
else {
if(point.x > 0.5 || (1 - point.x) <= point.y)
return ConnectionPointSide.South;
return ConnectionPointSide.West;
}
}
createParameters(parameters: ShapeParameters) {
}
normalizeParameters(shape: Shape, parameters: ShapeParameters) {
}
modifyParameters(shape: Shape, parameters: ShapeParameters, deltaX: number, deltaY: number) {
throw Error("Not implemented");
}
changeParameterValue(parameters: ShapeParameters, key: string, change: (p) => number) {
const p = parameters.get(key);
p.value = change(p);
}
getParameterPoints(shape: Shape): ShapeParameterPoint[] {
return [];
}
getExpandedSize(shape: Shape): Size {
return shape.size;
}
getCollapsedSize(shape: Shape): Size {
return shape.size;
}
getToolboxHeightToWidthRatio(width: number, height: number): number {
return height / width;
}
allowResizeHorizontally(_shape: Shape): boolean {
return true;
}
allowResizeVertically(_shape: Shape): boolean {
return true;
}
createPrimitives(shape: Shape, forToolbox?: boolean): SvgPrimitive<SVGGraphicsElement>[] {
let primitives: SvgPrimitive<SVGGraphicsElement>[] = [];
primitives = primitives.concat(this.createShapePrimitives(shape, forToolbox));
if(this.enableImage)
primitives = primitives.concat(this.createImagePrimitives(shape, forToolbox));
if(this.enableText)
primitives = primitives.concat(this.createTextPrimitives(shape, forToolbox));
return primitives;
}
abstract createShapePrimitives(shape: Shape, forToolbox?: boolean): SvgPrimitive<SVGGraphicsElement>[];
createImagePrimitives(_shape: Shape, _forToolbox: boolean): SvgPrimitive<SVGGraphicsElement>[] {
return [];
}
createTextPrimitives(shape: Shape, forToolbox?: boolean): SvgPrimitive<SVGGraphicsElement>[] {
if(shape.text === undefined || shape.text === "") return [];
const rect = this.getTextRectangle(shape);
return [
new TextPrimitive(rect.x, rect.y, shape.text, TextOwner.Shape, rect.width, rect.height, ShapeDescription.textSpacing,
shape.styleText, false, this.getTextClipPathId(forToolbox), undefined, this.getTextAngle()
)
];
}
getTextClipPathId(_forToolbox?: boolean): string {
return undefined;
}
getTextAngle(): TextAngle {
return TextAngle.Angle0deg;
}
getClientRectangle(shape: Shape): Rectangle {
return shape.rectangle;
}
getTextEditRectangle(shape: Shape): Rectangle {
return this.getTextRectangle(shape);
}
createSelectorPrimitives(shape: Shape): SvgPrimitive<SVGGraphicsElement>[] {
return [
new RectanglePrimitive(shape.position.x, shape.position.y, shape.size.width, shape.size.height, null, "selector")
];
}
protected raiseShapeDescriptionChanged(description: ShapeDescription): void {
this.onChanged.raise1(l => l.notifyShapeDescriptionChanged(description));
}
abstract getTextRectangle(shape: Shape): Rectangle;
abstract getSizeByText(textSize: Size, shape: Shape): Size;
}
export interface IShapeDescriptionChangesListener {
notifyShapeDescriptionChanged(description: ShapeDescription);
}