UNPKG

@kieler/klighd-core

Version:

Core KLighD diagram visualization with Sprotty

776 lines (691 loc) 21.6 kB
/* * KIELER - Kiel Integrated Environment for Layout Eclipse RichClient * * http://rtsys.informatik.uni-kiel.de/kieler * * Copyright 2019-2025 by * + Kiel University * + Department of Computer Science * + Real-Time and Embedded Systems Group * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. * * SPDX-License-Identifier: EPL-2.0 */ import { KEdge, KGraphData, KNode, SKGraphElement } from '@kieler/klighd-interactive/lib/constraint-classes' import { boundsFeature, layoutContainerFeature, moveFeature, popupFeature, RectangularPort, RGBColor, selectFeature, SLabelImpl, } from 'sprotty' import { Bounds, isBounds, Point } from 'sprotty-protocol' export const NODE_TYPE = 'node' export const EDGE_TYPE = 'edge' export const PORT_TYPE = 'port' export const LABEL_TYPE = 'label' /** * Represents the Sprotty version of its java counterpart in KLighD. */ export class SKNode extends KNode { hasFeature(feature: symbol): boolean { return ( feature === selectFeature || feature === boundsFeature || feature === layoutContainerFeature || (feature === moveFeature && (this.parent as SKNode).properties && ((this.parent as SKNode).properties['org.eclipse.elk.interactiveLayout'] as boolean)) || feature === popupFeature ) } override localToParent(point: Point | Bounds): Bounds { // `this` is the parent // `point` is the current element, containing its bounds const scaleFactor = (this.properties['org.eclipse.elk.topdown.scaleFactor'] as number) ?? 1 const result = { x: point.x * scaleFactor + this.position.x, y: point.y * scaleFactor + this.position.y, width: -1, height: -1, } if (isBounds(point)) { result.width = point.width * scaleFactor result.height = point.height * scaleFactor } return result } } /** * Represents the Sprotty version of its java counterpart in KLighD. */ export class SKPort extends RectangularPort implements SKGraphElement { trace?: string data: KGraphData[] areChildAreaChildrenRendered = false areNonChildAreaChildrenRendered = false hasFeature(feature: symbol): boolean { return feature === selectFeature || feature === boundsFeature || feature === popupFeature } properties: Record<string, unknown> } /** * Represents the Sprotty version of its java counterpart in KLighD. */ export class SKLabel extends SLabelImpl implements SKGraphElement { trace?: string data: KGraphData[] areChildAreaChildrenRendered? = false areNonChildAreaChildrenRendered? = false hasFeature(feature: symbol): boolean { // The boundsFeature here is additionally needed because bounds of labels need to be // estimated during the estimateTextBounds action. return feature === selectFeature || feature === boundsFeature || feature === popupFeature } properties: Record<string, unknown> } /** * Represents the Sprotty version of its java counterpart in KLighD. */ export class SKEdge extends KEdge { hasFeature(feature: symbol): boolean { return feature === selectFeature || feature === popupFeature } properties: Record<string, unknown> } /** * Element to define styles without attaching them to a specific rendering. * Represents its java counterpart in KLighD. */ export interface KStyleHolder { id: string styles: KStyle[] } /** * Abstract class to define members of a shapeType. * Represents its java counterpart in KLighD. */ export interface KRendering extends KGraphData, KStyleHolder { actions: KAction[] properties: Record<string, unknown> /** If this rendering is used as a clip rendering. Will not be set in the model and is to be used during rendering only. */ isClipRendering?: boolean } /** * Define a child area inside of a rendering to force children being placed inside the defined area. * Represents its java counterpart in KLighD. */ export type KChildArea = KRendering /** * KRendering that can have Children. * Represents its java counterpart in KLighD. */ export interface KContainerRendering extends KRendering { children: KRendering[] } /** * Draws an arc. Needs the startingAngle of the arc (0° = rightmost vertical line) on an ellipse and the angle the arc should cover (counterclockwise on the same ellipse). * Represents its java counterpart in KLighD. */ export interface KArc extends KContainerRendering { startAngle: number arcAngle: number arcType: Arc test: KPosition } /** * Represents its java counterpart in KLighD. */ export interface KCustomRendering extends KContainerRendering { className: string bundleName: string figureObject: Record<string, unknown> } /** * Define an ellipse shape that fits inside the space defined (a) by the node it is attached to or (b) by the placementData that is attached to the rendering. * Represents its java counterpart in KLighD. */ export type KEllipse = KContainerRendering /** * Use an image instead of defining the renderings completely by yourself. * Represents its java counterpart in KLighD. */ export interface KImage extends KContainerRendering { bundleName: string imagePath: string imageObject: Record<string, unknown> clipShape: KRendering } /** * Creates a polyline between two or more points. * Represents its java counterpart in KLighD. */ export interface KPolyline extends KContainerRendering { points: KPosition[] junctionPointRendering: KRendering } /** * Creates a polygon based on a list of points. The polygon is a closed figure (last point = first point) even when not defined explicitly. * Represents its java counterpart in KLighD. */ export type KPolygon = KPolyline /** * A polyline with rounded corners at its bendpoints. * Represents its java counterpart in KLighD. */ export interface KRoundedBendsPolyline extends KPolyline { bendRadius: number } /** * Creates a rounded edge. * Represents its java counterpart in KLighD. */ export type KSpline = KPolyline /** * Define a rectangle by adding the topLeft and bottomRight coordinates. * Represents its java counterpart in KLighD. */ export type KRectangle = KContainerRendering /** * The rounded rectangle is used to create a rectangle with rounded corners. Corner width and height need to be passed in order to define the style of the corners. * Represents its java counterpart in KLighD. */ export interface KRoundedRectangle extends KContainerRendering { cornerWidth: number cornerHeight: number } /** * References an already defined rendering to make redefining unnecessary. * Represents its java counterpart in KLighD. */ export interface KRenderingRef extends KRendering { rendering: KRendering } /** * Display text. Text can be positioned by adding Horizontal or VerticalAlignment and can be clipped if there is not enough space to display all of it without overlapping other * elements. * Represents its java counterpart in KLighD. */ export interface KText extends KRendering { text: string cursorSelectable: boolean editable: boolean } /** * Instances of this class may be employed in @see KGraphElement for accommodating * @see KRendering that are shared by multiple other @see KGraphElement * and referenced by means of @see KRenderingRef .<br> * A @see KRenderingRef can only represent a KRendering that is listed in the library here. * Represents its java counterpart in KLighD. */ export interface KRenderingLibrary extends KGraphData { renderings: KStyleHolder[] } /** * Performs action (ID) on event (@see Trigger ). * Represents its java counterpart in KLighD. */ export interface KAction { actionId: string trigger: Trigger altPressed: ModifierState ctrlCmdPressed: ModifierState shiftPressed: ModifierState } /** * The state of a modifier that it has to be in in order for some action to be performed. */ export enum ModifierState { DONT_CARE = 0, PRESSED = 1, NOT_PRESSED = 2, } /** * The literals mirror the constants java.awt.geom.Arc2D#OPEN, java.awt.geom.Arc2D#CHORD, and java.awt.geom.Arc2D#PIE. * This is to be leveraged in implementation, so be careful while modifying this enumeration. * Represents its java counterpart in KLighD. */ export enum Arc { /** * Plain arc without any closing line connection from end to beginning. */ OPEN = 0, /** * Arc with a straight closing line connection from end to beginning via the arc's center. */ CHORD = 1, /** * Arc with a straight closing line connection from end to beginning. */ PIE = 2, } /* * Used to set an absolute Position of a single point by defining x and y coordinates of this point relative to the parent. * The position can be set with absolute values or relative to the parent dimensions. * Represents its java counterpart in KLighD. */ export interface KPosition { x: KXPosition // TODO: has <?> in java y: KYPosition } /** * Define an x-position by setting absolute and relative position respective to a parent rendering. * Both parameters are always included in the calculation of the resulting position. See Subtypes for formula. * Can overlap the parent by setting negative values. * Represents its java counterpart in KLighD. */ export interface KXPosition { type: string absolute: number relative: number } /** * Defines a position starting at the leftmost point of the parent rendering. * pos = (L+absolute) + (R-L)*relative = (R-absolute) - widthOfParent*relative * Represents its java counterpart in KLighD. */ export type KLeftPosition = KXPosition /** * Defines a position starting at the rightmost point R of the parent rendering. * pos = (R-absolute) - (R-L)*relative = (R-absolute) - widthOfParent*relative * Represents its java counterpart in KLighD. */ export type KRightPosition = KXPosition /** * Define an y-position by setting absolute and relative position respective to a parent rendering. * Both parameters are always included in the calculation of the resulting position. See Subtypes for formula. * Can overlap the parent by setting negative values. * Represents its java counterpart in KLighD. */ export interface KYPosition { type: string absolute: number relative: number } /** * Defines a position starting at the highest point H of the parent rendering. * pos = (H+absolute) + (B-H)*relative * pos = (H+absolute) + heightOfParent*relative * Represents its java counterpart in KLighD. */ export type KTopPosition = KYPosition /** * Defines a position starting at the bottom point B of the parent rendering. * pos = (B-absolute) - (B-H-absolute)*relative * pos = (B-absolute) - heightOfParent*relative * Represents its java counterpart in KLighD. */ export type KBottomPosition = KYPosition /** * Represents its java counterpart in KLighD. */ export enum HorizontalAlignment { LEFT = 0, CENTER = 1, RIGHT = 2, } /** * Represents its java counterpart in KLighD. */ export enum VerticalAlignment { TOP = 0, CENTER = 1, BOTTOM = 2, } /** * Trigger presets to determine when to execute actions. * Represents its java counterpart in KLighD. */ export enum Trigger { /** * Fires on a left button's single click. * Note: Corresponding actions are not fired on the first click of a double, tripple, ... click. * Thus, triggering the actions is delayed by the system wide double click period for assuring the absence of subsequent clicks. * TODO: check if this is also true on the client! */ SINGLECLICK = 0, /** * Fires on left button's double (and more) click(s). */ DOUBLECLICK = 1, /** * Fires on left button's first click regardless if more clicks follow within the system wide double click period. */ SINGLE_OR_MULTICLICK = 2, /** * Fires on middle button's single click. * Note: Corresponding actions are not fired on the first click of a double, tripple, ... click. * Thus, triggering the actions is delayed by the system wide double click period for assuring the absence of subsequent clicks. */ MIDDLE_SINGLECLICK = 3, /** * Fires on middle button's double (and more) click(s). */ MIDDLE_DOUBLECLICK = 4, /** * Fires on middle button's first click regardless if more clicks follow within the system wide double click period. */ MIDDLE_SINGLE_OR_MULTICLICK = 5, } /** * Adds additional StyleInformation to a rendering. * Can be set to propagate to children to make redefining styles unnecessary. * Represents its java counterpart in KLighD. */ export interface KStyle { type: string propagateToChildren: boolean modifierId?: string selection: boolean } /** * Defines the alphaChannel and Color of an Object. * Represents its java counterpart in KLighD. */ export interface KColoring extends KStyle { color: RGBColor alpha: number targetColor?: RGBColor targetAlpha?: number gradientAngle: number } /** * Defines the BackgroundColor and its alphaChannel of a rendering. * Represents its java counterpart in KLighD. */ export type KBackground = KColoring /** * Defines the ForegroundColor and its alphaChannel of a rendering. * Represents its java counterpart in KLighD. */ export type KForeground = KColoring /** * FontStyle to determine whether to draw it bold or not. * Represents its java counterpart in KLighD. */ export interface KFontBold extends KStyle { bold: boolean } /** * FontStyle to determine whether to draw it italic or not. * Represents its java counterpart in KLighD. */ export interface KFontItalic extends KStyle { italic: boolean } /** * FontStyle to determine a desired font. * Represents its java counterpart in KLighD. */ export interface KFontName extends KStyle { name: string } /** * FontStyle to determine the size of the font. * Represents its java counterpart in KLighD. */ export interface KFontSize extends KStyle { size: number scaleWithZoom: boolean } /** * Represents its java counterpart in KLighD. */ export interface KHorizontalAlignment extends KStyle { horizontalAlignment: HorizontalAlignment } /** * Defines whether an object is visible or not. * Represents its java counterpart in KLighD. */ export interface KInvisibility extends KStyle { invisible: boolean } /** * Implements different line ending styles. * Represents its java counterpart in KLighD. */ export interface KLineCap extends KStyle { lineCap: LineCap } /** * Represents its java counterpart in KLighD. */ export interface KLineJoin extends KStyle { lineJoin: LineJoin miterLimit: number } /** * Defines the line style of a rendering by setting one of the available values of the LineStyle enumeration. * 'dashPattern' and 'dashOffset' are evaluated if and only if the literal 'CUSTOM' is chosen. * Represents its java counterpart in KLighD. */ export interface KLineStyle extends KStyle { lineStyle: LineStyle dashPattern?: number[] dashOffset: number } /** * Specifies a lineWidth for a rendering. * Represents its java counterpart in KLighD. */ export interface KLineWidth extends KStyle { lineWidth: number } /** * Specifies the (clockwise) rotation of the corresponding KRendering. * Represents its java counterpart in KLighD. */ export interface KRotation extends KStyle { rotation: number rotationAnchor: KPosition } /** * Represents its java counterpart in KLighD. */ export interface KShadow extends KStyle { xOffset: number yOffset: number blur: number color: RGBColor } /** * Special KStyle allowing to reference the styles of another KRendering or KStyleHolder in general. * Represents its java counterpart in KLighD. */ export interface KStyleRef extends KStyle { styleHolder: KStyleHolder // referencedTypes: Class<KStyle> } /** * FontStyle to add a strikeout to an text element. * Represents its java counterpart in KLighD. */ export interface KTextStrikeout extends KStyle { struckOut: boolean color: RGBColor } /** * FontStyle to add an underline to an text element. * Represents its java counterpart in KLighD. */ export interface KTextUnderline extends KStyle { underline: Underline color: RGBColor } /** * Represents its java counterpart in KLighD. */ export interface KVerticalAlignment extends KStyle { verticalAlignment: VerticalAlignment } /** * LineCapStyles analog to SWT LineCapStyles. * Represents its java counterpart in KLighD. */ export enum LineCap { CAP_FLAT = 0, CAP_ROUND = 1, CAP_SQUARE = 2, } /** * Represents its java counterpart in KLighD. */ export enum LineJoin { JOIN_MITER = 0, JOIN_ROUND = 1, JOIN_BEVEL = 2, } /** * LineStyles analog to SWT LineStyles. * Represents its java counterpart in KLighD. */ export enum LineStyle { SOLID = 0, DASH = 1, DOT = 2, DASHDOT = 3, DASHDOTDOT = 4, CUSTOM = 5, } /** * The style of an underline. Analog to SWT Underline. * Represents its java counterpart in KLighD. */ export enum Underline { NONE = 0, SINGLE = 1, DOUBLE = 2, ERROR = 3, SQUIGGLE = 4, LINK = 5, } /** * A data holder class for the result of evaluating a decorator. * Represents its java counterpart in KLighD. */ export interface Decoration { origin: Point bounds: Bounds rotation: number } // ----------- Rendering Class names ----------- // export const K_RENDERING_REF = 'KRenderingRefImpl' export const K_RENDERING_LIBRARY = 'KRenderingLibraryImpl' export const K_CHILD_AREA = 'KChildAreaImpl' export const K_CONTAINER_RENDERING = 'KContainerRenderingImpl' export const K_ARC = 'KArcImpl' export const K_CUSTOM_RENDERING = 'KCustomRenderingImpl' export const K_ELLIPSE = 'KEllipseImpl' export const K_IMAGE = 'KImageImpl' export const K_POLYLINE = 'KPolylineImpl' export const K_POLYGON = 'KPolygonImpl' export const K_ROUNDED_BENDS_POLYLINE = 'KRoundedBendsPolylineImpl' export const K_SPLINE = 'KSplineImpl' export const K_RECTANGLE = 'KRectangleImpl' export const K_ROUNDED_RECTANGLE = 'KRoundedRectangleImpl' export const K_TEXT = 'KTextImpl' /** * Returns if the given parameter is a KRendering. * instanceof cannot be used, because every rendering received by the server is typed as KGraphData and the real type can only be inferred using the type attribute. * @param test The potential KRendering. */ export function isRendering(test: KGraphData): test is KRendering { if (test === null) { return false } const { type } = test return ( type === K_RENDERING_REF || type === K_CHILD_AREA || type === K_CONTAINER_RENDERING || type === K_ARC || type === K_CUSTOM_RENDERING || type === K_ELLIPSE || type === K_IMAGE || type === K_POLYLINE || type === K_POLYGON || type === K_ROUNDED_BENDS_POLYLINE || type === K_SPLINE || type === K_RECTANGLE || type === K_ROUNDED_RECTANGLE || type === K_TEXT ) } /** * Returns if the given parameter is a KContainerRendering. * @param test The potential KContainerRendering. */ export function isContainerRendering(test: KGraphData): test is KContainerRendering { if (test === null) { return false } const { type } = test return ( type === K_CONTAINER_RENDERING || type === K_ARC || type === K_CUSTOM_RENDERING || type === K_ELLIPSE || type === K_IMAGE || type === K_POLYLINE || type === K_POLYGON || type === K_ROUNDED_BENDS_POLYLINE || type === K_SPLINE || type === K_RECTANGLE || type === K_ROUNDED_RECTANGLE ) } /** * Returns if the given parameter is a KPolyline. * @param test The potential KPolyline. */ export function isPolyline(test: KGraphData): test is KPolyline { if (test === null) { return false } const { type } = test return type === K_POLYLINE || type === K_POLYGON || type === K_ROUNDED_BENDS_POLYLINE || type === K_SPLINE } /** * Returns if the given parameter is a KText. * @param test The potential KText */ export function isKText(test: KGraphData): test is KText { if (test === null) { return false } const { type } = test return type === K_TEXT } /** * Returns if the given parameter is an SKGraphElement. * @param test The potential SKGraphElement. */ export function isSKGraphElement(test: unknown): test is SKGraphElement { if (test === null) { return false } const { type } = test as any return ( (type === NODE_TYPE || type === EDGE_TYPE || type === PORT_TYPE || type === LABEL_TYPE) && (test as any).data !== undefined && (test as any).properties !== undefined ) } /** * Returns if the given parameter is an SKLabel. * @param test The potential SKLabel. */ export function isSKLabel(test: unknown): test is SKLabel { if (test === null) { return false } const { type } = test as any return type === LABEL_TYPE && (test as any).data !== undefined && (test as any).properties !== undefined }