@kieler/klighd-core
Version:
Core KLighD diagram visualization with Sprotty
495 lines • 19.5 kB
JavaScript
"use strict";
/*
* KIELER - Kiel Integrated Environment for Layout Eclipse RichClient
*
* http://rtsys.informatik.uni-kiel.de/kieler
*
* Copyright 2021-2024 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
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RenderOptionsRegistry = exports.DebugOptions = exports.AnimateGoToBookmark = exports.Shadows = exports.ShadowOption = exports.MinimumLineWidth = exports.UseMinimumLineWidth = exports.TitleScalingFactor = exports.TextSimplificationThreshold = exports.SimplifySmallText = exports.FullDetailScaleThreshold = exports.FullDetailRelativeThreshold = exports.UseSmartZoom = exports.SmartZoom = exports.Appearance = exports.ShowConstraintOption = exports.ForceLightBackground = exports.ResizeToFit = exports.PinSidebarOption = void 0;
const inversify_1 = require("inversify");
const sprotty_protocol_1 = require("sprotty-protocol");
const registry_1 = require("../base/registry");
const services_1 = require("../services");
const actions_1 = require("./actions");
const option_models_1 = require("./option-models");
/**
* Whether the sidebar panel is pinned or not.
*/
class PinSidebarOption {
constructor() {
this.id = PinSidebarOption.ID;
this.name = PinSidebarOption.NAME;
this.type = option_models_1.TransformationOptionType.CHECK;
this.initialValue = PinSidebarOption.DEFAULT;
this.currentValue = PinSidebarOption.DEFAULT;
this.debug = true;
}
}
exports.PinSidebarOption = PinSidebarOption;
PinSidebarOption.ID = 'pin-sidebar';
PinSidebarOption.NAME = 'Pin Sidebar';
PinSidebarOption.DEFAULT = true;
/**
* Resize the diagram to fit the viewport if it is redrawn after a model update
* or a viewport resize.
* This has to have the same id as the corresponding FitToScreenAction.
*/
class ResizeToFit {
constructor() {
this.id = ResizeToFit.ID;
this.name = ResizeToFit.NAME;
// readonly tooltip: string = ResizeToFit.TOOLTIP;
this.type = option_models_1.TransformationOptionType.CHECK;
this.initialValue = ResizeToFit.DEFAULT;
this.description = 'Always resize to fit after diagram refresh.';
this.currentValue = ResizeToFit.DEFAULT;
this.debug = true;
}
}
exports.ResizeToFit = ResizeToFit;
ResizeToFit.ID = 'fit';
ResizeToFit.NAME = 'Resize To Fit on Refresh';
ResizeToFit.DEFAULT = true;
/**
* Uses a light background instead of an applied theme.
*/
class ForceLightBackground {
constructor() {
this.id = ForceLightBackground.ID;
this.name = ForceLightBackground.NAME;
this.type = option_models_1.TransformationOptionType.CHECK;
this.initialValue = ForceLightBackground.DEFAULT;
this.renderCategory = Appearance.ID;
this.description = 'Use light background regardless of the color scheme.';
this.currentValue = ForceLightBackground.DEFAULT;
}
}
exports.ForceLightBackground = ForceLightBackground;
ForceLightBackground.ID = 'force-light-background';
ForceLightBackground.NAME = 'Use Light Background';
ForceLightBackground.DEFAULT = false;
class ShowConstraintOption {
constructor() {
this.id = ShowConstraintOption.ID;
this.name = ShowConstraintOption.NAME;
this.type = option_models_1.TransformationOptionType.CHECK;
this.initialValue = false;
this.renderCategory = Appearance.ID;
this.description = 'Show marker for nodes that have interactive layout constraints set.';
this.currentValue = false;
}
}
exports.ShowConstraintOption = ShowConstraintOption;
ShowConstraintOption.ID = 'show-constraints';
ShowConstraintOption.NAME = 'Show Constraint';
class Appearance {
constructor() {
this.id = Appearance.ID;
this.name = Appearance.NAME;
this.type = option_models_1.TransformationOptionType.CATEGORY;
this.initialValue = true;
this.description = 'Appearance Category';
this.currentValue = true;
}
}
exports.Appearance = Appearance;
Appearance.ID = 'appearance';
Appearance.NAME = 'Appearance';
/**
* Smart Zoom category.
*/
class SmartZoom {
constructor() {
this.id = SmartZoom.ID;
this.name = SmartZoom.NAME;
this.type = option_models_1.TransformationOptionType.CATEGORY;
this.initialValue = true;
this.renderCategory = Appearance.ID;
this.description = 'Smart Zoom Category';
this.currentValue = true;
this.debug = true;
}
}
exports.SmartZoom = SmartZoom;
SmartZoom.ID = 'smart-zoom';
SmartZoom.NAME = 'Smart Zoom';
/**
* Boolean option to enable and disable the smart zoom feature.
* This corresponds to the automatic detail level of regions and states
* as well as limiting visible elements.
*/
class UseSmartZoom {
constructor() {
this.id = UseSmartZoom.ID;
this.name = UseSmartZoom.NAME;
this.type = option_models_1.TransformationOptionType.CHECK;
this.initialValue = true;
this.renderCategory = Appearance.ID;
this.description = 'Enables Smart Zoom';
this.currentValue = true;
}
}
exports.UseSmartZoom = UseSmartZoom;
UseSmartZoom.ID = 'use-smart-zoom';
UseSmartZoom.NAME = 'Smart Zoom';
/**
* Threshold for full detail level.
* Corresponds to the regions size compared to the current viewport.
*/
class FullDetailRelativeThreshold {
constructor() {
this.id = FullDetailRelativeThreshold.ID;
this.name = FullDetailRelativeThreshold.NAME;
this.type = option_models_1.TransformationOptionType.RANGE;
this.values = [];
this.range = {
first: 0.01,
second: 1,
};
this.stepSize = 0.01;
this.initialValue = FullDetailRelativeThreshold.DEFAULT;
this.renderCategory = SmartZoom.ID;
this.description = 'Shows all children of an element that uses at least the amount of the canvas.' +
'A value of 0.2 means an element is shown if its parent has at least 0.2 the size (minimum of width and height) of the canvas.';
this.currentValue = 0.2;
this.debug = true;
}
}
exports.FullDetailRelativeThreshold = FullDetailRelativeThreshold;
FullDetailRelativeThreshold.ID = 'full-detail-relative-threshold';
FullDetailRelativeThreshold.NAME = 'Full Detail Relative Threshold';
FullDetailRelativeThreshold.DEFAULT = 0.15;
/**
* Threshold for full detail level.
* Corresponds to the regions scale using the current viewport.
*/
class FullDetailScaleThreshold {
constructor() {
this.id = FullDetailScaleThreshold.ID;
this.name = FullDetailScaleThreshold.NAME;
this.type = option_models_1.TransformationOptionType.RANGE;
this.values = [];
this.range = {
first: 0.01,
second: 1,
};
this.stepSize = 0.01;
this.initialValue = FullDetailScaleThreshold.DEFAULT;
this.renderCategory = SmartZoom.ID;
this.description = 'Show an element if it can be rendered in at least the given amount of it original size.' +
'A value of 0.25 means an element is shown if it can be drawn in a fourth of its original height or width.';
this.currentValue = 0.25;
this.debug = true;
}
}
exports.FullDetailScaleThreshold = FullDetailScaleThreshold;
FullDetailScaleThreshold.ID = 'full-detail-scale-threshold';
FullDetailScaleThreshold.NAME = 'Full Detail Scale Threshold';
FullDetailScaleThreshold.DEFAULT = 0.25;
/**
* Boolean option toggling the use of text element replacement with rectangles.
*/
class SimplifySmallText {
constructor() {
this.id = SimplifySmallText.ID;
this.name = SimplifySmallText.NAME;
this.type = option_models_1.TransformationOptionType.CHECK;
this.initialValue = true;
this.renderCategory = SmartZoom.ID;
this.description = 'Whether illegible text is simplified to colored rectangles.';
this.currentValue = true;
this.debug = true;
}
}
exports.SimplifySmallText = SimplifySmallText;
SimplifySmallText.ID = 'simplify-small-text';
SimplifySmallText.NAME = 'Simplify Small Text';
/**
* Threshold under which text element simplification occurs in pixels.
*/
class TextSimplificationThreshold {
constructor() {
this.id = TextSimplificationThreshold.ID;
this.name = TextSimplificationThreshold.NAME;
this.type = option_models_1.TransformationOptionType.RANGE;
this.values = [];
this.range = {
first: 1,
second: 10,
};
this.stepSize = 0.1;
this.initialValue = TextSimplificationThreshold.DEFAULT;
this.renderCategory = SmartZoom.ID;
this.description = 'The threshold font size to simplify text.\nIf set to 3 a text which is 3 or less pixel high is simplified.';
this.currentValue = 3;
this.debug = true;
}
}
exports.TextSimplificationThreshold = TextSimplificationThreshold;
TextSimplificationThreshold.ID = 'text-simplification-threshold';
TextSimplificationThreshold.NAME = 'Text Simplification Threshold';
TextSimplificationThreshold.DEFAULT = 3;
/**
* The factor by which titles of collapsed regions get scaled by
* in relation to their size at native resolution.
*/
class TitleScalingFactor {
constructor() {
this.id = TitleScalingFactor.ID;
this.name = TitleScalingFactor.NAME;
this.type = option_models_1.TransformationOptionType.RANGE;
this.values = [];
this.range = {
first: 0.5,
second: 3,
};
this.stepSize = 0.01;
this.initialValue = TitleScalingFactor.DEFAULT;
this.renderCategory = SmartZoom.ID;
this.description = 'Factor to scale region titles compared to their original size.' +
'If set to 1 a region title be its original size (if the space permits) regardless of the zoom level.' +
'If it was 10 pixel high before it will always be 10 pixel high if the label can fit the region.';
this.currentValue = 1;
this.debug = true;
}
}
exports.TitleScalingFactor = TitleScalingFactor;
TitleScalingFactor.ID = 'title-scaling-factor';
TitleScalingFactor.NAME = 'Title Scaling Factor';
TitleScalingFactor.DEFAULT = 1;
/**
* Boolean option to toggle the scaling of lines based on zoom level.
*/
class UseMinimumLineWidth {
constructor() {
this.id = UseMinimumLineWidth.ID;
this.name = UseMinimumLineWidth.NAME;
this.type = option_models_1.TransformationOptionType.CHECK;
this.initialValue = true;
this.renderCategory = SmartZoom.ID;
this.description = "Whether all borders and lines are at least as wide as set by the corresponding 'Minimum Line Width' option.";
this.currentValue = true;
this.debug = true;
}
}
exports.UseMinimumLineWidth = UseMinimumLineWidth;
UseMinimumLineWidth.ID = 'use-minimum-line-width';
UseMinimumLineWidth.NAME = 'Minimum Line Width';
/**
* The size scaled lines should have as a minimum at any zoom level in pixels.
*/
class MinimumLineWidth {
constructor() {
this.id = MinimumLineWidth.ID;
this.name = MinimumLineWidth.NAME;
this.type = option_models_1.TransformationOptionType.RANGE;
this.values = [];
this.range = {
first: 0.1,
second: 3,
};
this.stepSize = 0.01;
this.initialValue = 0.5;
this.renderCategory = SmartZoom.ID;
this.description = 'The minium border or line width.\nIf set to 0.5 each edge or border is at least 0.5 pixel wide.';
this.currentValue = 0.5;
this.debug = true;
}
}
exports.MinimumLineWidth = MinimumLineWidth;
MinimumLineWidth.ID = 'minimum-line-width';
MinimumLineWidth.NAME = 'Minimum Line Width';
MinimumLineWidth.DEFAULT = 1;
var ShadowOption;
(function (ShadowOption) {
/** A real svg shadow. */
ShadowOption["PAPER_MODE"] = "Paper Mode";
/** The shape of the node drawn with different opacity multiple times behind the node. */
ShadowOption["KIELER_STYLE"] = "KIELER Style";
})(ShadowOption || (exports.ShadowOption = ShadowOption = {}));
/**
* The style shadows should be drawn in, either the paper mode shadows (nice, but slow in
* performance) or in default KIELER-style (fast, not as nice looking).
*/
class Shadows {
constructor() {
this.id = Shadows.ID;
this.name = Shadows.NAME;
this.type = option_models_1.TransformationOptionType.CHOICE;
this.initialValue = Shadows.DEFAULT;
this.renderCategory = Appearance.ID;
this.values = [ShadowOption.PAPER_MODE, ShadowOption.KIELER_STYLE];
this.description = 'The style shadows should be drawn in, either the paper mode shadows (nice, but slow in performance)' +
'or in default KIELER Style (fast, not as nice looking).' +
'KIELER Style draws multiple shapes in form of the node behind the node.' +
'Paper Mode uses SVG shadows.';
this.currentValue = Shadows.DEFAULT;
}
}
exports.Shadows = Shadows;
Shadows.ID = 'paper-shadows';
Shadows.NAME = 'Shadow Mode';
Shadows.DEFAULT = ShadowOption.KIELER_STYLE;
/**
* Whether going to a Bookmark should be animated
*/
class AnimateGoToBookmark {
constructor() {
this.id = AnimateGoToBookmark.ID;
this.name = AnimateGoToBookmark.NAME;
this.type = option_models_1.TransformationOptionType.CHECK;
this.initialValue = AnimateGoToBookmark.DEFAULT;
this.currentValue = true;
}
}
exports.AnimateGoToBookmark = AnimateGoToBookmark;
AnimateGoToBookmark.ID = 'animate-go-to-bookmark';
AnimateGoToBookmark.NAME = 'Animate Go To Bookmark';
AnimateGoToBookmark.DEFAULT = true;
/**
* Boolean option to toggle debug options.
*/
class DebugOptions {
constructor() {
this.id = DebugOptions.ID;
this.name = DebugOptions.NAME;
this.type = option_models_1.TransformationOptionType.CHECK;
this.initialValue = false;
this.description = 'Whether debug options should be shown.';
this.currentValue = false;
}
}
exports.DebugOptions = DebugOptions;
DebugOptions.ID = 'debug-options';
DebugOptions.NAME = 'Debug Options';
/** {@link Registry} that stores and updates different render options. */
let RenderOptionsRegistry = class RenderOptionsRegistry extends registry_1.Registry {
constructor() {
super();
this._renderOptions = new Map();
// Add available render options to this registry
// Debug
this.register(DebugOptions);
this.register(ResizeToFit);
this.register(PinSidebarOption);
this.register(AnimateGoToBookmark);
// Appearance
this.register(Appearance);
this.register(ForceLightBackground);
this.register(ShowConstraintOption);
this.register(Shadows);
// Smart Zoom
this.register(SmartZoom);
this.register(UseSmartZoom);
this.register(FullDetailRelativeThreshold);
this.register(FullDetailScaleThreshold);
this.register(SimplifySmallText);
this.register(TextSimplificationThreshold);
this.register(TitleScalingFactor);
this.register(UseMinimumLineWidth);
this.register(MinimumLineWidth);
}
init() {
this.storage.getItem('render').then((data) => {
if (data)
this.loadPersistedData(data);
});
}
/**
* Restores options that where previously persisted in storage. Since render
* options are not provided by the server, they have to be retrieved from storage.
*/
loadPersistedData(data) {
for (const entry of Object.entries(data)) {
const option = this._renderOptions.get(entry[0]);
if (option) {
// eslint-disable-next-line prefer-destructuring
option.currentValue = entry[1];
}
}
this.notifyListeners();
}
/** Registers a single render option. */
register(Option) {
this._renderOptions.set(Option.ID, new Option());
}
/** Convenience method to register all given options in order. */
registerAll(...Options) {
Options.forEach((Option) => this.register(Option));
}
/** Unregisters a single render option. */
unregister(Option) {
return this._renderOptions.delete(Option.ID);
}
/** Convenience method to unregister all given options in order. */
unregisterAll(...Options) {
return Options.every((Option) => this.unregister(Option));
}
/** Handles the render options actions. */
// eslint-disable-next-line consistent-return
handle(action) {
if (actions_1.SetRenderOptionAction.isThisAction(action)) {
const option = this._renderOptions.get(action.id);
if (option) {
option.currentValue = action.value;
this.notifyListeners();
}
}
else if (actions_1.ResetRenderOptionsAction.isThisAction(action)) {
this._renderOptions.forEach((option) => {
option.currentValue = option.initialValue;
});
this.notifyListeners();
}
else {
return sprotty_protocol_1.UpdateModelAction.create([], { animate: false, cause: action });
}
}
get allRenderOptions() {
return Array.from(this._renderOptions.values());
}
getValue(Option) {
var _a;
return (_a = this._renderOptions.get(Option.ID)) === null || _a === void 0 ? void 0 : _a.currentValue;
}
getValueOrDefault(Option) {
var _a;
return (_a = this.getValue(Option)) !== null && _a !== void 0 ? _a : Option.DEFAULT;
}
};
exports.RenderOptionsRegistry = RenderOptionsRegistry;
__decorate([
(0, inversify_1.inject)(services_1.ServiceTypes.PersistenceStorage),
__metadata("design:type", Object)
], RenderOptionsRegistry.prototype, "storage", void 0);
__decorate([
(0, inversify_1.postConstruct)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], RenderOptionsRegistry.prototype, "init", null);
exports.RenderOptionsRegistry = RenderOptionsRegistry = __decorate([
(0, inversify_1.injectable)(),
__metadata("design:paramtypes", [])
], RenderOptionsRegistry);
//# sourceMappingURL=render-options-registry.js.map