@kieler/klighd-core
Version:
Core KLighD diagram visualization with Sprotty
741 lines • 35.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_LINE_CAP_SVG = exports.DEFAULT_CORNER_HEIGHT = exports.DEFAULT_CORNER_WIDTH = exports.DEFAULT_SHADOW_DEF = exports.DEFAULT_SHADOW = exports.DEFAULT_K_VERTICAL_ALIGNMENT = exports.DEFAULT_VERTICAL_ALIGNMENT = exports.DEFAULT_FOREGROUND = exports.DEFAULT_CLICKABLE_FILL = exports.DEFAULT_FILL = exports.DEFAULT_K_LINE_WIDTH = exports.DEFAULT_LINE_WIDTH = exports.DEFAULT_K_LINE_STYLE = exports.DEFAULT_LINE_STYLE = exports.DEFAULT_K_LINE_JOIN = exports.DEFAULT_MITER_LIMIT = exports.DEFAULT_LINE_JOIN = exports.DEFAULT_K_LINE_CAP = exports.DEFAULT_LINE_CAP = exports.DEFAULT_K_INVISIBILITY = exports.DEFAULT_INVISIBILITY = exports.DEFAULT_K_HORIZONTAL_ALIGNMENT = exports.DEFAULT_HORIZONTAL_ALIGNMENT = exports.DEFAULT_K_FONT_SIZE = exports.DEFAULT_FONT_SIZE = exports.DEFAULT_K_FONT_NAME = exports.DEFAULT_FONT_NAME = exports.DEFAULT_K_FONT_ITALIC = exports.DEFAULT_FONT_ITALIC = exports.DEFAULT_K_FONT_BOLD = exports.DEFAULT_FONT_BOLD = exports.K_VERTICAL_ALIGNMENT = exports.K_TEXT_UNDERLINE = exports.K_TEXT_STRIKEOUT = exports.K_STYLE_REF = exports.K_SHADOW = exports.K_ROTATION = exports.K_LINE_WIDTH = exports.K_LINE_STYLE = exports.K_LINE_JOIN = exports.K_LINE_CAP = exports.K_INVISIBILITY = exports.K_HORIZONTAL_ALIGNMENT = exports.K_FONT_SIZE = exports.K_FONT_NAME = exports.K_FONT_ITALIC = exports.K_FONT_BOLD = exports.K_FOREGROUND = exports.K_BACKGROUND = exports.K_COLORING = void 0;
exports.getSvgTextStyles = exports.getSvgLineStyles = exports.isInvisible = exports.getSvgColorStyle = exports.getSvgColorStyles = exports.getSvgShadowStyles = exports.shadowDefinition = exports.colorDefinition = exports.copyStyles = exports.applyKStyle = exports.getDefaultNonTextSelectionStyles = exports.getDefaultTextSelectionStyles = exports.getKStyles = exports.KStyles = exports.DEFAULT_MITER_LIMIT_SVG = exports.DEFAULT_LINE_JOIN_SVG = void 0;
const sprotty_1 = require("sprotty"); // eslint-disable-line @typescript-eslint/no-unused-vars
const render_options_registry_1 = require("./options/render-options-registry");
const skgraph_models_1 = require("./skgraph-models");
const views_common_1 = require("./views-common");
// ----------------------------- type string definitions for all styles ------------------------------------- //
exports.K_COLORING = 'KColoringImpl';
exports.K_BACKGROUND = 'KBackgroundImpl';
exports.K_FOREGROUND = 'KForegroundImpl';
exports.K_FONT_BOLD = 'KFontBoldImpl';
exports.K_FONT_ITALIC = 'KFontItalicImpl';
exports.K_FONT_NAME = 'KFontNameImpl';
exports.K_FONT_SIZE = 'KFontSizeImpl';
exports.K_HORIZONTAL_ALIGNMENT = 'KHorizontalAlignmentImpl';
exports.K_INVISIBILITY = 'KInvisibilityImpl';
exports.K_LINE_CAP = 'KLineCapImpl';
exports.K_LINE_JOIN = 'KLineJoinImpl';
exports.K_LINE_STYLE = 'KLineStyleImpl';
exports.K_LINE_WIDTH = 'KLineWidthImpl';
exports.K_ROTATION = 'KRotationImpl';
exports.K_SHADOW = 'KShadowImpl';
exports.K_STYLE_REF = 'KStyleRefImpl';
exports.K_TEXT_STRIKEOUT = 'KTextStrikeoutImpl';
exports.K_TEXT_UNDERLINE = 'KTextUnderlineImpl';
exports.K_VERTICAL_ALIGNMENT = 'KVerticalAlignmentImpl';
// constants for string building
const GRADIENT_UNIT_OBJECT_BOUNDING_BOX = 'objectBoundingBox';
const RGB_START = 'rgb(';
const RGB_END = ')';
const URL_START = 'url(#';
const URL_END = ')';
// Default values for most Styles, that are used if no style is given Default values taken from PNodeController.java
exports.DEFAULT_FONT_BOLD = false;
exports.DEFAULT_K_FONT_BOLD = {
bold: exports.DEFAULT_FONT_BOLD,
};
exports.DEFAULT_FONT_ITALIC = false;
exports.DEFAULT_K_FONT_ITALIC = {
italic: exports.DEFAULT_FONT_ITALIC,
};
exports.DEFAULT_FONT_NAME = 'Overpass, sans-serif';
exports.DEFAULT_K_FONT_NAME = {
name: exports.DEFAULT_FONT_NAME,
};
exports.DEFAULT_FONT_SIZE = 10;
exports.DEFAULT_K_FONT_SIZE = {
size: exports.DEFAULT_FONT_SIZE,
scaleWithZoom: false, // TODO: implement this
};
exports.DEFAULT_HORIZONTAL_ALIGNMENT = skgraph_models_1.HorizontalAlignment.CENTER;
exports.DEFAULT_K_HORIZONTAL_ALIGNMENT = {
horizontalAlignment: exports.DEFAULT_HORIZONTAL_ALIGNMENT,
};
exports.DEFAULT_INVISIBILITY = false;
exports.DEFAULT_K_INVISIBILITY = {
invisible: exports.DEFAULT_INVISIBILITY,
};
exports.DEFAULT_LINE_CAP = skgraph_models_1.LineCap.CAP_FLAT;
exports.DEFAULT_K_LINE_CAP = {
lineCap: exports.DEFAULT_LINE_CAP,
};
exports.DEFAULT_LINE_JOIN = skgraph_models_1.LineJoin.JOIN_MITER;
exports.DEFAULT_MITER_LIMIT = 10;
exports.DEFAULT_K_LINE_JOIN = {
lineJoin: exports.DEFAULT_LINE_JOIN,
miterLimit: exports.DEFAULT_MITER_LIMIT,
};
exports.DEFAULT_LINE_STYLE = skgraph_models_1.LineStyle.SOLID;
exports.DEFAULT_K_LINE_STYLE = {
lineStyle: exports.DEFAULT_LINE_STYLE,
dashOffset: 0,
dashPattern: [0],
};
exports.DEFAULT_LINE_WIDTH = 1;
exports.DEFAULT_K_LINE_WIDTH = {
lineWidth: exports.DEFAULT_LINE_WIDTH,
};
exports.DEFAULT_FILL = {
color: 'none',
};
exports.DEFAULT_CLICKABLE_FILL = {
color: `${RGB_START}0,0,0${RGB_END}`,
opacity: '0',
};
exports.DEFAULT_FOREGROUND = {
color: 'black',
};
exports.DEFAULT_VERTICAL_ALIGNMENT = skgraph_models_1.VerticalAlignment.CENTER;
exports.DEFAULT_K_VERTICAL_ALIGNMENT = {
verticalAlignment: exports.DEFAULT_VERTICAL_ALIGNMENT,
};
exports.DEFAULT_SHADOW = undefined;
exports.DEFAULT_SHADOW_DEF = undefined;
exports.DEFAULT_CORNER_WIDTH = 0;
exports.DEFAULT_CORNER_HEIGHT = 0;
exports.DEFAULT_LINE_CAP_SVG = 'butt';
exports.DEFAULT_LINE_JOIN_SVG = 'miter';
exports.DEFAULT_MITER_LIMIT_SVG = '4';
/**
* Data class to hold each possible KStyle of any rendering. Defaults each style to undefined or its default value from PNodeController.java
*/
class KStyles {
constructor(initialize) {
if (initialize !== false) {
this.kBackground = undefined;
this.kForeground = undefined;
this.kFontBold = exports.DEFAULT_K_FONT_BOLD;
this.kFontItalic = exports.DEFAULT_K_FONT_ITALIC;
this.kFontName = exports.DEFAULT_K_FONT_NAME;
this.kFontSize = exports.DEFAULT_K_FONT_SIZE;
this.kHorizontalAlignment = exports.DEFAULT_K_HORIZONTAL_ALIGNMENT;
this.kInvisibility = exports.DEFAULT_K_INVISIBILITY;
this.kLineCap = exports.DEFAULT_K_LINE_CAP;
this.kLineJoin = exports.DEFAULT_K_LINE_JOIN;
this.kLineStyle = exports.DEFAULT_K_LINE_STYLE;
this.kLineWidth = exports.DEFAULT_K_LINE_WIDTH;
this.kRotation = undefined;
this.kShadow = exports.DEFAULT_SHADOW;
this.kStyleRef = undefined;
this.kTextStrikeout = undefined;
this.kTextUnderline = undefined;
this.kVerticalAlignment = exports.DEFAULT_K_VERTICAL_ALIGNMENT;
}
}
}
exports.KStyles = KStyles;
/**
* Calculates the renderings for all styles contained in styleList into an object.
* @param styleList The list of all styles that should have their rendering calculated.
* @param propagatedStyles The styles propagated from parent elements that should be taken into account.
* @param stylesToPropagate The optional styles object that should be propagated further to children. It is modified in this method.
*/
function getKStyles(parent, styleHolder, propagatedStyles, context, stylesToPropagate) {
// TODO: not all of these are implemented yet
// Style Priority in KLighD:
// 1. Styles propagated from immedeate parent renderings
// 2. Styles propagated from recursive parent rendering (deeper down in the hierarchy first)
// 3. Styles explicitly given to the rendering
// 4. Default styles
// Caution: Styles that are propagated do NOT apply to the rendering itself, if there are parent propagated styles. Only the children will have this propagated style as their first priority.
// The styles to propagate start as the current propagated styles to be overwritten by new styles.
const styles = new KStyles();
if (stylesToPropagate !== undefined) {
copyStyles(propagatedStyles, stylesToPropagate);
}
let styleList = styleHolder.styles;
if (styleList === undefined) {
return styles;
}
// First, check if we need to incorporate default selection styles.
// That is the case if the parend is selected and no selection styles are available.
if ((0, sprotty_1.isSelectable)(parent) && parent.selected) {
if (styleList.filter((style) => style.selection === true).length === 0) {
// ...if no selection styles are available, apply default ones.
if ((0, skgraph_models_1.isKText)(styleHolder)) {
styleList = styleList.concat(getDefaultTextSelectionStyles());
}
else if (styleHolder === (0, views_common_1.getKRendering)(parent.data, context)) {
// For non-text renderings this only applies to the root rendering
styleList = styleList.concat(getDefaultNonTextSelectionStyles());
}
}
}
// Then, apply all styles in order of appereance in the style list.
for (const style of styleList) {
// Only apply selection styles if the parent is selected.
if (style.selection === false || ((0, sprotty_1.isSelectable)(parent) && parent.selected)) {
applyKStyle(style, styles, stylesToPropagate);
}
}
// Finally, override with propagated styles.
copyStyles(propagatedStyles, styles);
return styles;
}
exports.getKStyles = getKStyles;
/**
* The default selection styles for text renderings.
* @returns A list of default selection text styles.
*/
function getDefaultTextSelectionStyles() {
return [
{
type: exports.K_BACKGROUND,
propagateToChildren: false,
selection: true,
color: {
red: 190,
green: 190,
blue: 190,
},
alpha: 255,
gradientAngle: 0,
},
{
type: exports.K_FONT_BOLD,
propagateToChildren: false,
selection: true,
bold: true,
},
];
}
exports.getDefaultTextSelectionStyles = getDefaultTextSelectionStyles;
/**
* The default selection styles for non-text renderings.
* @returns A list of default selection non-text styles.
*/
function getDefaultNonTextSelectionStyles() {
return [
{
type: exports.K_BACKGROUND,
propagateToChildren: false,
selection: true,
color: {
red: 190,
green: 190,
blue: 190,
},
alpha: 255,
gradientAngle: 0,
},
{
type: exports.K_LINE_STYLE,
propagateToChildren: false,
selection: true,
lineStyle: skgraph_models_1.LineStyle.DASH,
dashOffset: 0,
},
];
}
exports.getDefaultNonTextSelectionStyles = getDefaultNonTextSelectionStyles;
/**
* Apply the given style to the given styles object. If it should be propagated, also apply it to the stylesToPropagage object.
* @param style The style to apply.
* @param styles The styles object the style should be applied to.
* @param stylesToPropagage The styles object that gets propagated.
*/
function applyKStyle(style, styles, stylesToPropagage) {
switch (style.type) {
case exports.K_COLORING: {
console.error(`A style can not be a ${style.type} by itself, it needs to be a subclass of it.`);
break;
}
case exports.K_BACKGROUND: {
styles.kBackground = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kBackground = styles.kBackground;
}
break;
}
case exports.K_FOREGROUND: {
styles.kForeground = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kForeground = styles.kForeground;
}
break;
}
case exports.K_FONT_BOLD: {
styles.kFontBold = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kFontBold = styles.kFontBold;
}
break;
}
case exports.K_FONT_ITALIC: {
styles.kFontItalic = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kFontItalic = styles.kFontItalic;
}
break;
}
case exports.K_FONT_NAME: {
styles.kFontName = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kFontName = styles.kFontName;
}
break;
}
case exports.K_FONT_SIZE: {
styles.kFontSize = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kFontSize = styles.kFontSize;
}
break;
}
case exports.K_HORIZONTAL_ALIGNMENT: {
styles.kHorizontalAlignment = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kHorizontalAlignment = styles.kHorizontalAlignment;
}
break;
}
case exports.K_INVISIBILITY: {
styles.kInvisibility = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kInvisibility = styles.kInvisibility;
}
break;
}
case exports.K_LINE_CAP: {
styles.kLineCap = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kLineCap = styles.kLineCap;
}
break;
}
case exports.K_LINE_JOIN: {
styles.kLineJoin = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kLineJoin = styles.kLineJoin;
}
break;
}
case exports.K_LINE_STYLE: {
styles.kLineStyle = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kLineStyle = styles.kLineStyle;
}
break;
}
case exports.K_LINE_WIDTH: {
styles.kLineWidth = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kLineWidth = styles.kLineWidth;
}
break;
}
case exports.K_ROTATION: {
styles.kRotation = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kRotation = styles.kRotation;
}
break;
}
case exports.K_SHADOW: {
styles.kShadow = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kShadow = styles.kShadow;
}
break;
}
case exports.K_STYLE_REF: {
console.error(`The style ${style.type} is not implemented yet.`);
// style as KStyleRef
// special case! TODO: how to handle this? Never seen this in any rendering
break;
}
case exports.K_TEXT_STRIKEOUT: {
console.error(`The style ${style.type} is not implemented yet.`);
styles.kTextStrikeout = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kTextStrikeout = styles.kTextStrikeout;
}
break;
}
case exports.K_TEXT_UNDERLINE: {
styles.kTextUnderline = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kTextUnderline = styles.kTextUnderline;
}
break;
}
case exports.K_VERTICAL_ALIGNMENT: {
styles.kVerticalAlignment = style;
if (style.propagateToChildren === true && stylesToPropagage !== undefined) {
stylesToPropagage.kVerticalAlignment = styles.kVerticalAlignment;
}
break;
}
default: {
console.error(`Unexpected Style found while rendering: ${style.type}`);
break;
}
}
}
exports.applyKStyle = applyKStyle;
/**
* Copies the content from one to the other KStyles object.
* @param from The KStyles to copy from.
* @param to The KStyles to copy to.
*/
function copyStyles(from, to) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
to.kBackground = (_a = from.kBackground) !== null && _a !== void 0 ? _a : to.kBackground;
to.kForeground = (_b = from.kForeground) !== null && _b !== void 0 ? _b : to.kForeground;
to.kFontBold = (_c = from.kFontBold) !== null && _c !== void 0 ? _c : to.kFontBold;
to.kFontItalic = (_d = from.kFontItalic) !== null && _d !== void 0 ? _d : to.kFontItalic;
to.kFontName = (_e = from.kFontName) !== null && _e !== void 0 ? _e : to.kFontName;
to.kFontSize = (_f = from.kFontSize) !== null && _f !== void 0 ? _f : to.kFontSize;
to.kHorizontalAlignment = (_g = from.kHorizontalAlignment) !== null && _g !== void 0 ? _g : to.kHorizontalAlignment;
to.kInvisibility = (_h = from.kInvisibility) !== null && _h !== void 0 ? _h : to.kInvisibility;
to.kLineCap = (_j = from.kLineCap) !== null && _j !== void 0 ? _j : to.kLineCap;
to.kLineJoin = (_k = from.kLineJoin) !== null && _k !== void 0 ? _k : to.kLineJoin;
to.kLineStyle = (_l = from.kLineStyle) !== null && _l !== void 0 ? _l : to.kLineStyle;
to.kLineWidth = (_m = from.kLineWidth) !== null && _m !== void 0 ? _m : to.kLineWidth;
to.kRotation = (_o = from.kRotation) !== null && _o !== void 0 ? _o : to.kRotation;
to.kShadow = (_p = from.kShadow) !== null && _p !== void 0 ? _p : to.kShadow;
to.kStyleRef = (_q = from.kStyleRef) !== null && _q !== void 0 ? _q : to.kStyleRef;
to.kTextStrikeout = (_r = from.kTextStrikeout) !== null && _r !== void 0 ? _r : to.kTextStrikeout;
to.kTextUnderline = (_s = from.kTextUnderline) !== null && _s !== void 0 ? _s : to.kTextUnderline;
to.kVerticalAlignment = (_t = from.kVerticalAlignment) !== null && _t !== void 0 ? _t : to.kVerticalAlignment;
}
exports.copyStyles = copyStyles;
// ----------------------------- Functions for rendering different KStyles as VNodes in svg --------------------------------------------
/**
* SVG element for color gradient definition.
* @param colorId The unique identifying string for this color.
* @param start The SVG data for the start color of the gradient.
* @param end The SVG data for the end color of the gradient.
* @param angle The angle at which the gradient should flow.
*/
function colorDefinition(colorId, start, end, angle) {
const startColorStop = ((0, sprotty_1.svg)("stop", { offset: 0, style: Object.assign({ 'stop-color': start.color }, (start.opacity ? { 'stop-opacity': start.opacity } : {})) }));
const endColorStop = ((0, sprotty_1.svg)("stop", { offset: 1, style: Object.assign({ 'stop-color': end.color }, (end.opacity ? { 'stop-opacity': end.opacity } : {})) }));
let angleFloat = angle === undefined ? 0 : angle;
// Calculate the x and y lengths a line of angle 'angle' would have in a 1x1 box.
// First, normalize the angle to be 0<=angle<360
angleFloat %= 360;
if (angleFloat < 0) {
angleFloat += 360;
}
// Convert the angle to radians
const angleRad = (angleFloat / 180) * Math.PI;
let x;
let y;
if (angleRad <= (1 / 4) * Math.PI || angleRad > (7 / 4) * Math.PI) {
x = 1;
y = -Math.tan((0 / 2) * Math.PI - angleRad);
}
else if (angleRad <= (3 / 4) * Math.PI) {
x = Math.tan((1 / 2) * Math.PI - angleRad);
y = 1;
}
else if (angleRad <= (5 / 4) * Math.PI) {
x = -1;
y = Math.tan((2 / 2) * Math.PI - angleRad);
}
else {
// or: else if (angleRad <= 7/4 * Math.PI) {
x = -Math.tan((3 / 2) * Math.PI - angleRad);
y = -1;
}
// Now, turn these lengths into x1/x2 and y1/y2 coordinates within the box such that 0<=var<=1,
// centered within the box.
let x1;
let x2;
let y1;
let y2;
if (x >= 0) {
const halfRemain = (1 - x) / 2;
x1 = halfRemain;
x2 = halfRemain + x;
}
else {
const halfRemain = (1 + x) / 2;
x1 = halfRemain - x;
x2 = halfRemain;
}
if (y >= 0) {
const halfRemain = (1 - y) / 2;
y1 = halfRemain;
y2 = halfRemain + y;
}
else {
const halfRemain = (1 + y) / 2;
y1 = halfRemain - y;
y2 = halfRemain;
}
const gradientAttributes = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ id: colorId }, (angleFloat === 0 ? {} : { gradientUnits: GRADIENT_UNIT_OBJECT_BOUNDING_BOX })), (angleFloat === 0 ? {} : { x1 })), (angleFloat === 0 ? {} : { x2 })), (angleFloat === 0 ? {} : { y1 })), (angleFloat === 0 ? {} : { y2 }));
return ((0, sprotty_1.svg)("linearGradient", Object.assign({}, gradientAttributes),
startColorStop,
endColorStop));
}
exports.colorDefinition = colorDefinition;
/**
* SVG element for a shadow definition.
* @param shadowId The unique identifying string for this shadow.
* @param color The color of the shadow.
* @param blur The amount of blur of the shadow.
* @param xOffset The x-offset of the shadow.
* @param yOffset The y-offset of the shadow.
*/
function shadowDefinition(shadowId, color, blur, xOffset, yOffset) {
// stdDev of 1 looks closest to KIELER style shadows, but looks nicer with this blur
// TODO: ultimately, this should be using the blur parameter again.
// TODO: use the color given in the shadow.
// TODO: maybe calculate the blurClip depending on the calculated size of the rendering and the x- and y-offset.
const STD_DEV = 1;
const blurClip = 25;
return ((0, sprotty_1.svg)("filter", { id: shadowId,
// Extend the region around the element in which the shadow should be rendered.
x: `-${blurClip}%`, y: `-${blurClip}%`, width: `${100 + 2 * blurClip}%`, height: `${100 + 2 * blurClip}%` },
(0, sprotty_1.svg)("feGaussianBlur", { in: "SourceAlpha", stdDeviation: STD_DEV }),
(0, sprotty_1.svg)("feOffset", {
// A smaller offset causes the blur not to overlap too much.
dx: xOffset / 4, dy: yOffset / 4, result: "offsetblur" }),
(0, sprotty_1.svg)("feFlood", null),
(0, sprotty_1.svg)("feComposite", { in2: "offsetblur", operator: "in" }),
(0, sprotty_1.svg)("feMerge", null,
(0, sprotty_1.svg)("feMergeNode", null),
(0, sprotty_1.svg)("feMergeNode", { in: "SourceGraphic" }))));
// The above definition is equivalent to this shorthand SVG, but not all SVG renderers support and understand this (such as Inkscape).
// As every shadow is defined exactly once in the final SVG, this additional code does not add too much to the overall file size.
// <feDropShadow
// dx={ xOffset / 4 }
// dy={ yOffset / 4 }
// stdDeviation={ STD_DEV }
// />
}
exports.shadowDefinition = shadowDefinition;
/**
* Returns the identifying string for the given shadow style, that can be put into the SVG 'filter' attribute.
* Also remembers the shadow definition in the rendering context to be added to the top of the final SVG.
* @param styles The KStyles of the rendering.
* @param context The rendering context.
*/
function getSvgShadowStyles(styles, context) {
const shadow = styles.kShadow;
if (shadow === undefined) {
return undefined;
}
// Every shadow ID should start with an 's'.
let shadowId = 's';
let color;
const { blur } = shadow;
const { xOffset } = shadow;
const { yOffset } = shadow;
// Extract the color and also put it in the ID.
if (shadow.color !== undefined) {
const shadowColor = `${shadow.color.red},${shadow.color.green},${shadow.color.blue}`;
shadowId += shadowColor;
color = RGB_START + shadowColor + RGB_END;
}
// Separator for unique identification.
shadowId += '$';
// Add the blur to the ID.
if (blur !== undefined) {
shadowId += blur;
}
shadowId += '$';
// Add the x- and y-offset to the ID.
if (xOffset !== undefined) {
shadowId += xOffset;
}
shadowId += '$';
if (yOffset !== undefined) {
shadowId += yOffset;
}
// Remember the shadow definition to be added at the top level of the SVG, if the same shadow has not been defined previously.
if (!context.renderingDefs.has(shadowId)) {
context.renderingDefs.set(shadowId, shadowDefinition(shadowId, color, blur, xOffset, yOffset));
}
// Return the reference of the above defined ID to be put in the filter attribute of any SVG element.
return URL_START + shadowId + URL_END;
}
exports.getSvgShadowStyles = getSvgShadowStyles;
/**
* Returns the identifying strings for the given foreground- and background styles that can be put in the SVG 'stroke' and 'fill' attributes,
* depending on the rendering the styles have to be applied for.
* The identifying string can either be a simple rgb color reference (such as rgb(0,0,0) for black), a rgba color reference (such as rgba(0,0,0,128) for a transparent black)
* or a url for a gradient color definition that is remembered in the rendering context and has to be added to the SVG later.
* @param styles The KStyles of the rendering.
* @param context The rendering context.
*/
function getSvgColorStyles(styles, context, parent) {
const foreground = getSvgColorStyle(styles.kForeground, context);
const background = getSvgColorStyle(styles.kBackground, context);
const grayedOutColor = { color: 'grey', opacity: '255' };
if (parent instanceof skgraph_models_1.SKEdge && parent.moved) {
// edge should be greyed out
return {
foreground: grayedOutColor,
background: background === undefined ? exports.DEFAULT_FILL : grayedOutColor,
opacity: String(parent.opacity),
};
}
if (parent instanceof skgraph_models_1.SKNode && parent.shadow) {
// colors of the shadow node
return {
foreground: grayedOutColor,
background: background === undefined ? exports.DEFAULT_FILL : { color: 'gainsboro', opacity: '255' },
opacity: String(parent.opacity),
};
}
if (parent instanceof skgraph_models_1.SKNode && parent.highlight) {
return {
foreground: { color: '#03A9F4', opacity: '255' },
background: background === undefined ? exports.DEFAULT_FILL : background,
opacity: parent.opacity.toString(),
};
}
return {
foreground: foreground === undefined ? exports.DEFAULT_FOREGROUND : foreground,
background: background === undefined ? exports.DEFAULT_FILL : background,
opacity: String(parent.opacity),
};
}
exports.getSvgColorStyles = getSvgColorStyles;
/**
* The same as getSvgColorStyles, only that it only handles one of the two styles.
* @param coloring The KColoring of which the color string should be returned.
* @param context The rendering context.
* @see getSvgColorStyles
*/
function getSvgColorStyle(coloring, context) {
if (coloring === undefined || coloring.color === undefined) {
return undefined;
}
// If the color is a single color, just return its corresponding rgb resp. rgba color.
if ((0, views_common_1.isSingleColor)(coloring)) {
return (0, views_common_1.fillSingleColor)(coloring);
}
// Otherwise, build an ID for the gradient color to refer to the definition described below.
// Every color ID should start with a 'c'.
let colorId = 'c';
const start = {};
const end = {};
let angle;
if (coloring.alpha !== undefined && coloring.alpha !== 255) {
start.opacity = (coloring.alpha / 255).toString();
}
const startColor = `${coloring.color.red},${coloring.color.green},${coloring.color.blue}`;
colorId += startColor;
start.color = RGB_START + startColor + RGB_END;
// Separate the individual parts in the ID to guarantee uniqueness.
colorId += '$';
// Do the same for the end color.
if (coloring.targetAlpha !== undefined && coloring.targetAlpha !== 255) {
end.opacity = (coloring.targetAlpha / 255).toString();
}
const endColor = `${coloring.targetColor.red},${coloring.targetColor.green},${coloring.targetColor.blue}`;
colorId += endColor;
end.color = RGB_START + endColor + RGB_END;
// Add the angle of the gradient to the ID.
if (coloring.gradientAngle !== 0) {
angle = coloring.gradientAngle;
colorId += `$${angle}`;
}
// Remember the color definition to be added at the top level of the SVG, if the same color has not been defined previously.
if (!context.renderingDefs.has(colorId)) {
context.renderingDefs.set(colorId, colorDefinition(colorId, start, end, angle));
}
// Return the reference of the above defined ID to be put in the fill or stroke attribute of any SVG element.
return {
color: URL_START + colorId + URL_END,
// no opacity needed here as it is already in the gradient color definition.
};
}
exports.getSvgColorStyle = getSvgColorStyle;
/**
* Returns if the rendering should be rendered or if it is invisible and only its children are relevant.
* @param styles The KStyles of the rendering.
*/
function isInvisible(styles) {
return styles.kInvisibility !== undefined && styles.kInvisibility.invisible;
}
exports.isInvisible = isInvisible;
/**
* Returns the SVG strings for line styles that can be applied to the following SVG attributes:
* 'stroke-linecap' has to be set to the lineCap style,
* 'stroke-linejoin' has to be set to the lineJoin style,
* 'stroke-width' has to be set to the lineWidth style,
* 'stroke-dasharray' has to be set to the dashArray style,
* 'stroke-miterlimit' has to be set to the miterLimit style. (This is not a string, but a number.)
* @param styles The KStyles of the rendering.
* @param target The target of the line
* @param context The current rendering context
*/
function getSvgLineStyles(styles, target, context) {
var _a;
// The line width as requested by the element
let lineWidth = styles.kLineWidth === undefined ? exports.DEFAULT_LINE_WIDTH : styles.kLineWidth.lineWidth;
const useLineWidthOption = context.renderOptionsRegistry.getValue(render_options_registry_1.UseMinimumLineWidth);
// Only enable, if option is found.
const useMinimumLineWidth = useLineWidthOption !== null && useLineWidthOption !== void 0 ? useLineWidthOption : false;
if (!context.forceRendering && useMinimumLineWidth) {
// The line witdh in px that the drawn line should not be less than.
const minimumLineWidth = context.renderOptionsRegistry.getValueOrDefault(render_options_registry_1.MinimumLineWidth);
// The line width the requested one would have when rendered in the current zoom level.
const realLineWidth = lineWidth * (0, sprotty_1.getZoom)(target);
if (realLineWidth !== 0 && realLineWidth < minimumLineWidth) {
// scale the used line width up to appear as big as the minimum line width requested.
lineWidth *= minimumLineWidth / realLineWidth;
}
}
const lineCap = styles.kLineCap === undefined ? undefined : (0, views_common_1.lineCapText)(styles.kLineCap);
const lineJoin = styles.kLineJoin === undefined ? undefined : (0, views_common_1.lineJoinText)(styles.kLineJoin);
const miterLimit = ((_a = styles.kLineJoin) === null || _a === void 0 ? void 0 : _a.miterLimit) === undefined ? exports.DEFAULT_MITER_LIMIT : styles.kLineJoin.miterLimit;
return {
lineWidth: lineWidth === exports.DEFAULT_LINE_WIDTH ? undefined : `${lineWidth}px`,
lineCap: lineCap === exports.DEFAULT_LINE_CAP_SVG ? undefined : lineCap,
lineJoin: lineJoin === exports.DEFAULT_LINE_JOIN_SVG ? undefined : lineJoin,
dashArray: styles.kLineStyle === undefined ? undefined : (0, views_common_1.lineStyleText)(styles.kLineStyle, lineWidth),
// Note: Here the miter limit value is also omitted if the value equals KGraph's default value of 10, because otherwise the resulting SVG would
// always contain the miterLimit style to be set to 10, even though it is not intended by the creator of the KGraph model and it would not
// even make any difference in the rendering. Here I cannot distinguish if the model creator really wanted to have the specific miter limit of 10
// or if he just does not care. As the first case seems rare, I prefer a cleaner resulting svg here.
miterLimit: lineJoin !== 'miter' || String(miterLimit) === exports.DEFAULT_MITER_LIMIT_SVG || miterLimit === exports.DEFAULT_MITER_LIMIT
? undefined
: String(miterLimit),
};
}
exports.getSvgLineStyles = getSvgLineStyles;
/**
* Returns the SVG strings for text styles that can be applied to the following SVG attributes:
* 'dominant-baseline' has to be set to the dominantBaseline style,
* 'font-family' has to be set to the fontFamily style,
* 'font-size' has to be set to the fontSize style,
* 'font-style' has to be set to the fontStyle style,
* 'font-weight' has to be set to the fontWeight style,
* 'text-decoration-line' has to be set to the textDecorationLine style,
* 'text-decoration-style' has to be set to the textDecorationStyle style.
* @param styles The KStyles of the rendering.
*/
function getSvgTextStyles(styles) {
var _a;
return {
dominantBaseline: (0, views_common_1.verticalAlignmentText)(((_a = styles.kVerticalAlignment) === null || _a === void 0 ? void 0 : _a.verticalAlignment) === undefined
? exports.DEFAULT_VERTICAL_ALIGNMENT
: styles.kVerticalAlignment.verticalAlignment),
fontFamily: styles.kFontName === undefined ? undefined : (0, views_common_1.camelToKebab)(styles.kFontName.name),
// Convert pt to px here with a default value of 96 dpi(px/in) and 72pt/in, making this a conversion from in to px.
fontSize: styles.kFontSize === undefined ? undefined : `${(styles.kFontSize.size * 96) / 72}px`,
fontStyle: styles.kFontItalic === undefined || styles.kFontItalic.italic === exports.DEFAULT_FONT_ITALIC
? undefined
: 'italic',
fontWeight: styles.kFontBold === undefined || styles.kFontBold.bold === exports.DEFAULT_FONT_BOLD ? undefined : 'bold',
textDecorationLine: styles.kTextUnderline === undefined || styles.kTextUnderline.underline === skgraph_models_1.Underline.NONE
? undefined
: 'underline',
textDecorationStyle: styles.kTextUnderline === undefined
? undefined
: (0, views_common_1.textDecorationStyleText)(styles.kTextUnderline),
// textDecorationColor: styles.kTextUnderline === undefined ? undefined : textDecorationColor(styles.kTextUnderline as KTextUnderline),
// TODO: textDecorationColorDefinition:
};
}
exports.getSvgTextStyles = getSvgTextStyles;
//# sourceMappingURL=views-styles.js.map