Browse Source

UI: Improve scada symbol editor

pull/11391/head
Igor Kulikov 2 years ago
parent
commit
b034cd1532
  1. 1
      ui-ngx/package.json
  2. 379
      ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg.models.ts
  3. 1
      ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.html
  4. 143
      ui-ngx/src/styles.scss
  5. 9
      ui-ngx/yarn.lock

1
ui-ngx/package.json

@ -45,6 +45,7 @@
"@ngx-translate/core": "^14.0.0",
"@svgdotjs/svg.filter.js": "^3.0.8",
"@svgdotjs/svg.js": "^3.2.0",
"@svgdotjs/svg.panzoom.js": "^2.1.2",
"@tinymce/tinymce-angular": "^7.0.0",
"ace-builds": "1.4.13",
"ace-diff": "^3.0.3",

379
ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg.models.ts

@ -16,7 +16,8 @@
import { ValueType } from '@shared/models/constants';
import * as svgjs from '@svgdotjs/svg.js';
import { Box, Element, Rect, Runner, SVG, Svg, Text } from '@svgdotjs/svg.js';
import { Box, Element, Rect, Runner, SVG, Svg, Text, Timeline, Style } from '@svgdotjs/svg.js';
import '@svgdotjs/svg.panzoom.js';
import {
DataToValueType,
GetValueAction,
@ -45,6 +46,7 @@ import { ResizeObserver } from '@juggle/resize-observer';
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
import ITooltipPosition = JQueryTooltipster.ITooltipPosition;
import ITooltipsterHelper = JQueryTooltipster.ITooltipsterHelper;
import TooltipPositioningSide = JQueryTooltipster.TooltipPositioningSide;
export interface IotSvgApi {
formatValue: (value: any, dec?: number, units?: string, showZeroDecimals?: boolean) => string | undefined;
@ -281,30 +283,36 @@ export class IotSvgEditObject {
private box: Box;
private elements: IotSvgElement[] = [];
private readonly shapeResize$: ResizeObserver;
private performSetup = false;
private hoverFilterStyle: Style;
public scale = 1;
constructor(private rootElement: HTMLElement) {
this.shapeResize$ = new ResizeObserver(() => {
this.resize();
});
this.shapeResize$.observe(this.rootElement);
}
public setContent(svgContent: string) {
this.shapeResize$.unobserve(this.rootElement);
if (this.svgShape) {
this.elements.length = 0;
this.svgShape.remove();
}
const doc: XMLDocument = new DOMParser().parseFromString(svgContent, 'image/svg+xml');
this.svgShape = SVG().svg(doc.documentElement.innerHTML);
this.svgShape = SVG().addTo(this.rootElement).svg(doc.documentElement.innerHTML);
this.svgShape.node.style.overflow = 'visible';
this.svgShape.node.style['user-select'] = 'none';
this.box = this.svgShape.bbox();
this.svgShape.size(this.box.width, this.box.height);
this.svgShape.addTo(this.rootElement);
this.resize();
//this.svgShape.cre
this.svgShape.style().rule('.hovered', {filter: 'drop-shadow(0px 0px 1px #FFC107)'});
//this.svgShape.style().rule('.hovered', {filter: 'opacity(50%)'});
this.svgShape.viewbox(`0 0 ${this.box.width} ${this.box.height}`);
this.svgShape.style().rule('.tb-element', {cursor: 'pointer', transition: '0.2s filter ease-in-out'});
this.updateHoverFilterStyle();
this.performSetup = true;
this.shapeResize$.observe(this.rootElement);
}
private doSetup() {
this.setupZoomPan(0);
(window as any).SVG = svgjs;
forkJoin([
from(import('tooltipster')),
@ -314,6 +322,49 @@ export class IotSvgEditObject {
});
}
private setupZoomPan(margin: number) {
this.svgShape.on('zoom', (e) => {
const {
detail: { level, focus }
} = e as any;
this.svgShape.zoom(level, focus);
const box = this.restrictToMargins(this.svgShape.viewbox(), margin);
this.svgShape.viewbox(box);
setTimeout(() => {
this.updateTooltipPositions();
});
e.preventDefault();
});
this.svgShape.on('panning', (e) => {
const box = (e as any).detail.box;
this.svgShape.viewbox(this.restrictToMargins(box, margin));
setTimeout(() => {
this.updateTooltipPositions();
});
e.preventDefault();
});
this.svgShape.on('panStart', (e) => {
this.svgShape.node.style.cursor = 'grab';
});
this.svgShape.on('panEnd', (e) => {
this.svgShape.node.style.cursor = 'default';
});
}
private restrictToMargins(box: Box, margin: number): Box {
if (box.x < -margin) {
box.x = -margin;
} else if ((box.x + box.width) > (this.box.width + margin)) {
box.x = this.box.width + margin - box.width;
}
if (box.y < -margin) {
box.y = -margin;
} else if ((box.y + box.height) > (this.box.height + margin)) {
box.y = this.box.height + margin - box.height;
}
return box;
}
private setupElements() {
this.svgShape.children().forEach(child => {
this.addElement(child);
@ -343,9 +394,20 @@ export class IotSvgEditObject {
}
}
for (const group of overlappingGroups) {
let offset = - (elementTooltipMinHeight * group.length) / 2 + elementTooltipMinHeight / 2;
const centers = group.map(e => e.box.cy);
const center = centers.reduce((a, b) => a + b, 0) / centers.length;
const textElement = group.find(e => e.isText());
const slots = textElement ? group.length % 2 === 0 ? (group.length + 1) : group.length : group.length;
if (textElement) {
textElement.setInnerTooltipOffset(0, center);
group.splice(group.indexOf(textElement), 1);
}
let offset = - (elementTooltipMinHeight * slots) / 2 + elementTooltipMinHeight / 2;
for (const element of group) {
element.innerTooltipOffset = offset;
if (textElement && offset === 0) {
offset += elementTooltipMinHeight;
}
element.setInnerTooltipOffset(offset, center);
offset += elementTooltipMinHeight;
}
}
@ -376,12 +438,55 @@ export class IotSvgEditObject {
if (this.svgShape) {
const targetWidth = this.rootElement.getBoundingClientRect().width;
const targetHeight = this.rootElement.getBoundingClientRect().height;
let scale: number;
if (targetWidth < targetHeight) {
this.scale = targetWidth / this.box.width;
scale = targetWidth / this.box.width;
} else {
this.scale = targetHeight / this.box.height;
scale = targetHeight / this.box.height;
}
if (this.scale !== scale) {
this.scale = scale;
this.svgShape.node.style.transform = `scale(${this.scale})`;
this.updateHoverFilterStyle();
this.updateZoomOptions();
this.updateTooltipPositions();
}
if (this.performSetup) {
this.performSetup = false;
this.doSetup();
}
this.svgShape.node.style.transform = `scale(${this.scale})`;
}
}
private updateHoverFilterStyle() {
if (this.hoverFilterStyle) {
this.hoverFilterStyle.remove();
}
const whiteBlur = (2.8 / this.scale).toFixed(2);
const blackBlur = (1.2 / this.scale).toFixed(2);
this.hoverFilterStyle =
this.svgShape.style().rule('.hovered',
{
filter:
`drop-shadow(0px 0px ${whiteBlur}px white) drop-shadow(0px 0px ${whiteBlur}px white)
drop-shadow(0px 0px ${whiteBlur}px white) drop-shadow(0px 0px ${whiteBlur}px white)
drop-shadow(0px 0px ${blackBlur}px black)`
}
);
}
private updateZoomOptions() {
this.svgShape.panZoom({
zoomMin: 1,
zoomMax: 4,
zoomFactor: 2 / this.scale
});
}
private updateTooltipPositions() {
const container = this.rootElement.getBoundingClientRect();
for (const e of this.elements) {
e.updateTooltipPosition(container);
}
}
@ -390,8 +495,8 @@ export class IotSvgEditObject {
const hasBBox = (e: Element): boolean => {
try {
if (e.bbox) {
e.bbox();
return true;
const box = e.bbox();
return !!box.width || !!box.height;
} else {
return false;
}
@ -402,31 +507,45 @@ const hasBBox = (e: Element): boolean => {
const textTooltip = (el: JQuery<any>, text: string) => {
el.tooltipster({
theme: ['tooltipster-tb'],
theme: ['iot-svg'],
trigger: 'hover',
content: text
});
};
const isDomRectContained = (target: DOMRect, container: DOMRect, horizontalGap = 0, verticalGap = 0): boolean => (
target.left >= container.left - horizontalGap &&
target.left + target.width <= container.left + container.width + horizontalGap &&
target.top >= container.top - verticalGap &&
target.top + target.height <= container.top + container.height + verticalGap
);
const elementTooltipMinHeight = 36 + 8;
const elementTooltipMinWidth = 100;
const groupRectStroke = 10;
const groupRectStroke = 2;
const groupRectPadding = 2;
class IotSvgElement {
private highlightRect: Rect;
private highlightRectTimeline: Timeline;
private tooltip: ITooltipsterInstance;
private tag: string;
public innerTooltipOffset = 0;
private isEditing = false;
private innerTooltipOffset = 0;
public readonly box: Box;
private highlighted = false;
private tooltipMouseX: number;
private tooltipMouseY: number;
constructor(private editObject: IotSvgEditObject,
private element: Element) {
this.tag = element.attr('tb:tag');
@ -437,10 +556,18 @@ class IotSvgElement {
if (this.isGroup()) {
this.highlightRect =
this.editObject.svgShape
.rect(this.box.width + this.unscaled(groupRectStroke * 4), this.box.height + this.unscaled(groupRectStroke * 4))
.x(this.box.x - this.unscaled(groupRectStroke * 2))
.y(this.box.y - this.unscaled(groupRectStroke * 2))
.attr({fill: 'none', stroke: '#ccc', 'stroke-width': this.unscaled(groupRectStroke), opacity: 0});
.rect(this.box.width + groupRectPadding * 2, this.box.height + groupRectPadding * 2)
.x(this.box.x - groupRectPadding)
.y(this.box.y - groupRectPadding)
.attr({
fill: 'none',
rx: this.unscaled(6),
stroke: 'rgba(0, 0, 0, 0.38)',
'stroke-dasharray': '1',
'stroke-width': this.unscaled(groupRectStroke),
opacity: 0});
this.highlightRectTimeline = new Timeline();
this.highlightRect.timeline(this.highlightRectTimeline);
this.highlightRect.hide();
} else {
this.element.addClass('tb-element');
@ -470,18 +597,22 @@ class IotSvgElement {
if (!this.highlighted) {
this.highlighted = true;
if (this.isGroup()) {
this.highlightRect.width(this.box.width + this.unscaled(groupRectStroke * 4))
.height(this.box.height + this.unscaled(groupRectStroke * 4))
.x(this.box.x - this.unscaled(groupRectStroke * 2))
.y(this.box.y - this.unscaled(groupRectStroke * 2))
.attr({'stroke-width': this.unscaled(groupRectStroke)});
this.highlightRectTimeline.finish();
this.highlightRect
.attr({
rx: this.unscaled(6),
'stroke-width': this.unscaled(groupRectStroke)
});
this.highlightRect.show();
this.highlightRect.animate(300).attr({opacity: 1});
} else {
this.element.addClass('hovered');
}
if (this.hasTag()) {
this.tooltip.reposition();
if (!this.isEditing) {
this.tooltip.reposition();
}
$(this.tooltip.elementTooltip()).addClass('tb-active');
}
}
}
@ -490,12 +621,16 @@ class IotSvgElement {
if (this.highlighted) {
this.highlighted = false;
if (this.isGroup()) {
this.highlightRectTimeline.finish();
this.highlightRect.animate(300).attr({opacity: 0}).after(() => {
this.highlightRect.hide();
});
} else {
this.element.removeClass('hovered');
}
if (this.hasTag()) {
$(this.tooltip.elementTooltip()).removeClass('tb-active');
}
}
}
@ -503,6 +638,7 @@ class IotSvgElement {
this.tooltip.destroy();
this.tag = null;
this.element.attr('tb:tag', null);
this.unhighlight();
this.createAddTagTooltip();
}
@ -513,8 +649,31 @@ class IotSvgElement {
this.createTagTooltip();
}
public updateTooltipPosition(container: DOMRect) {
if (this.tooltip && !this.tooltip.status().destroyed) {
this.tooltip.reposition();
const tooltipElement = this.tooltip.elementTooltip();
if (tooltipElement) {
if (isDomRectContained(tooltipElement.getBoundingClientRect(), container,
elementTooltipMinWidth, elementTooltipMinHeight)) {
tooltipElement.style.visibility = null;
} else {
tooltipElement.style.visibility = 'hidden';
}
}
}
}
public setInnerTooltipOffset(offset: number, center: number) {
this.innerTooltipOffset = offset + (center - this.box.cy) * this.editObject.scale;
}
private unscaled(size: number): number {
return size / this.editObject.scale;
return size / (this.editObject.scale * this.editObject.svgShape.zoom());
}
private scaled(size: number): number {
return size * (this.editObject.scale * this.editObject.svgShape.zoom());
}
private createTagTooltip() {
@ -522,17 +681,26 @@ class IotSvgElement {
el.tooltipster(
{
arrow: this.isGroup(),
distance: this.isGroup() ? 20 : 6,
theme: ['tooltipster-tb'],
distance: this.isGroup() ? (this.scaled(groupRectPadding) + groupRectStroke) : 6,
theme: ['iot-svg'],
delay: 0,
animationDuration: 0,
interactive: true,
trigger: 'custom',
side: 'top',
trackOrigin: true,
trackOrigin: false,
content: '',
functionPosition: (instance, helper, position) =>
this.innerTooltipPosition(instance, helper, position)
this.innerTagTooltipPosition(instance, helper, position),
functionReady: (instance, helper) => {
const tooltipEl = $(helper.tooltip);
tooltipEl.on('mouseenter', () => {
this.highlight();
});
tooltipEl.on('mouseleave', () => {
this.unhighlight();
});
}
}
);
this.tooltip = el.tooltipster('instance');
@ -540,6 +708,8 @@ class IotSvgElement {
}
private setupTagPanel() {
this.isEditing = false;
this.unhighlight();
const tagPanel =
$(`<div style="display: flex; flex-direction: row; align-items: center; gap: 8px;">
<span>${this.element.type}:</span>
@ -547,12 +717,6 @@ class IotSvgElement {
<span style="cursor: pointer;" class="edit-icon mat-icon tb-mat-18 material-icons">edit</span>
<span style="cursor: pointer;" class="delete-icon mat-icon tb-mat-18 material-icons">delete</span>
</div>`);
tagPanel.on('mouseenter', () => {
this.highlight();
});
tagPanel.on('mouseleave', () => {
this.unhighlight();
});
const updateTagButton = tagPanel.find('.edit-icon');
textTooltip(updateTagButton, 'Update tag');
updateTagButton.on('click', () => {
@ -568,6 +732,7 @@ class IotSvgElement {
}
private setupEditTagPanel() {
this.isEditing = true;
const editTagInputPanel =
$(`<div style="display: flex; flex-direction: row; align-items: center; gap: 8px;">
<span>Update tag:</span>
@ -621,17 +786,38 @@ class IotSvgElement {
const el = $(this.element.node);
el.tooltipster(
{
arrow: this.isGroup(),
distance: this.isGroup() ? 20 : 6,
theme: ['tooltipster-tb'],
delay: 200,
arrow: true,
theme: ['iot-svg', 'tb-active'],
delay: [0, 300],
interactive: true,
trigger: 'hover',
side: 'top',
trackOrigin: true,
side: ['top', 'left', 'bottom', 'right'],
trackOrigin: false,
content: '',
functionBefore: (instance, helper) => {
const mouseEvent = (helper.event as MouseEvent);
this.tooltipMouseX = mouseEvent.clientX;
this.tooltipMouseY = mouseEvent.clientY;
let side: TooltipPositioningSide;
if (this.isGroup()) {
side = 'top';
} else {
side = this.calculateTooltipSide(helper.origin.getBoundingClientRect(),
mouseEvent.clientX, mouseEvent.clientY);
}
instance.option('side', side);
},
functionPosition: (instance, helper, position) =>
this.innerTooltipPosition(instance, helper, position)
this.innerAddTagTooltipPosition(instance, helper, position),
functionReady: (instance, helper) => {
const tooltipEl = $(helper.tooltip);
tooltipEl.on('mouseenter', () => {
this.highlight();
});
tooltipEl.on('mouseleave', () => {
this.unhighlight();
});
}
}
);
this.tooltip = el.tooltipster('instance');
@ -639,6 +825,7 @@ class IotSvgElement {
}
private setupAddTagPanel() {
this.isEditing = false;
const addTagPanel =
$(`<div style="display: flex; flex-direction: row; align-items: center; gap: 8px;">
<span>${this.element.type}:</span>
@ -653,6 +840,7 @@ class IotSvgElement {
}
private setupAddTagInputPanel() {
this.isEditing = true;
const addTagInputPanel =
$(`<div style="display: flex; flex-direction: row; align-items: center; gap: 8px;">
<span>Enter tag:</span>
@ -666,50 +854,141 @@ class IotSvgElement {
textTooltip(applyTagButton, 'Apply');
textTooltip(closeButton, 'Cancel');
let addPanelClosed = false;
tagInput.on('keypress', (event) => {
if (event.which === 13) {
const newTag: string = tagInput.val() as string;
if (newTag) {
addPanelClosed = true;
this.setTag(newTag);
}
}
});
applyTagButton.on('click', () => {
const newTag: string = tagInput.val() as string;
addPanelClosed = true;
if (newTag) {
this.setTag(newTag);
} else {
this.unhighlight();
this.tooltip.close();
}
});
closeButton.on('click', () => {
addPanelClosed = true;
this.unhighlight();
this.tooltip.close();
});
tagInput.on('blur', () => {
setTimeout(() => {
if (!addPanelClosed) {
addPanelClosed = true;
this.tooltip.close();
}
});
});
this.tooltip.content(addTagInputPanel);
this.tooltip.option('delay', [0, 10000000]);
this.tooltip.on('closing', () => {
this.tooltip.option('delay', [0, 300]);
this.setupAddTagPanel();
});
tagInput.trigger('focus');
}
private innerTooltipPosition(instance: ITooltipsterInstance, helper: ITooltipsterHelper, position: ITooltipPosition): ITooltipPosition {
private innerTagTooltipPosition(instance: ITooltipsterInstance, helper: ITooltipsterHelper,
position: ITooltipPosition): ITooltipPosition {
const clientRect = helper.origin.getBoundingClientRect();
if (!this.isGroup()) {
const clientRect = helper.origin.getBoundingClientRect();
position.coord.top = clientRect.top + (clientRect.height - position.size.height) / 2
+ this.innerTooltipOffset;
+ this.innerTooltipOffset * this.editObject.svgShape.zoom();
position.coord.left = clientRect.left + (clientRect.width - position.size.width) / 2;
} else {
position.distance = this.scaled(groupRectPadding) + groupRectStroke;
position.coord.top = clientRect.top - position.size.height - (this.scaled(groupRectPadding) + groupRectStroke);
}
return position;
}
private innerAddTagTooltipPosition(instance: ITooltipsterInstance,
helper: ITooltipsterHelper, position: ITooltipPosition): ITooltipPosition {
const distance = 10;
switch (position.side) {
case 'right':
position.coord.top = this.tooltipMouseY - position.size.height / 2;
position.coord.left = this.tooltipMouseX + distance;
position.target = this.tooltipMouseY;
break;
case 'top':
position.coord.top = this.tooltipMouseY - position.size.height - distance;
position.coord.left = this.tooltipMouseX - position.size.width / 2;
position.target = this.tooltipMouseX;
if (this.isGroup()) {
position.coord.top -= elementTooltipMinHeight;
}
break;
case 'left':
position.coord.top = this.tooltipMouseY - position.size.height / 2;
position.coord.left = this.tooltipMouseX - position.size.width - distance;
position.target = this.tooltipMouseY;
break;
case 'bottom':
position.coord.top = this.tooltipMouseY + distance;
position.coord.left = this.tooltipMouseX - position.size.width / 2;
position.target = this.tooltipMouseX;
break;
}
return position;
}
private calculateTooltipSide(clientRect: DOMRect, mouseX: number, mouseY: number): TooltipPositioningSide {
let side: TooltipPositioningSide;
const cx = clientRect.left + clientRect.width / 2;
const cy = clientRect.top + clientRect.height / 2;
if (clientRect.width > clientRect.height) {
if (Math.abs(cx - mouseX) > clientRect.width / 4) {
if (mouseX < cx) {
side = 'left';
} else {
side = 'right';
}
} else {
if (mouseY < cy) {
side = 'top';
} else {
side = 'bottom';
}
}
} else {
if (Math.abs(cy - mouseY) > clientRect.height / 4) {
if (mouseY < cy) {
side = 'top';
} else {
side = 'bottom';
}
} else {
if (mouseX < cx) {
side = 'left';
} else {
side = 'right';
}
}
}
return side;
}
private hasTag() {
return !!this.tag;
}
private isGroup() {
public isGroup() {
return this.element.type === 'g';
}
public isText() {
return this.element.type === 'text';
}
}
export class IotSvgObject {

1
ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.component.html

@ -27,6 +27,7 @@
<tb-details-panel fxFlex
[isReadOnly]="true"
[showCloseDetails]="false"
headerHeightPx="64"
headerTitle="{{symbolData?.imageResource?.title}}">
<div>
{{ metadata | json }}

143
ui-ngx/src/styles.scss

@ -460,6 +460,149 @@ mat-icon {
}
}
.tooltipster-sidetip.iot-svg {
.tooltipster-box {
user-select: none;
background: rgba(0, 0, 0, 0.54);
border: 1px solid rgba(0, 0, 0, 0);
border-radius: 8px;
.tooltipster-content {
padding: 4px 8px;
font-size: 12px;
line-height: 12px;
font-weight: 500;
color: #ffffff;
}
}
&.tb-active {
.tooltipster-box {
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.38);
box-shadow: 0 0 10px 6px rgba(0, 0, 0, .2);
.tooltipster-content {
color: #000;
}
}
.tooltipster-arrow {
.tooltipster-arrow-uncropped {
.tooltipster-arrow-background {
border-width: 12px;
}
}
}
&.tooltipster-top {
.tooltipster-arrow {
bottom: -1px;
.tooltipster-arrow-uncropped {
.tooltipster-arrow-border {
border-top-color: rgba(0, 0, 0, 0.38);
}
.tooltipster-arrow-background {
border-top-color: #fff;
left: -2px;
}
}
}
}
&.tooltipster-bottom {
.tooltipster-arrow {
top: -1px;
.tooltipster-arrow-uncropped {
.tooltipster-arrow-border {
border-bottom-color: rgba(0, 0, 0, 0.38);
}
.tooltipster-arrow-background {
border-bottom-color: #fff;
left: -2px;
top: -1px;
}
}
}
}
&.tooltipster-left {
.tooltipster-arrow {
right: -1px;
.tooltipster-arrow-uncropped {
.tooltipster-arrow-border {
border-left-color: rgba(0, 0, 0, 0.38);
}
.tooltipster-arrow-background {
border-left-color: #fff;
top: -2px;
}
}
}
}
&.tooltipster-right {
.tooltipster-arrow {
left: -1px;
.tooltipster-arrow-uncropped {
.tooltipster-arrow-border {
border-right-color: rgba(0, 0, 0, 0.38);
}
.tooltipster-arrow-background {
border-right-color: #fff;
top: -2px;
left: -1px;
}
}
}
}
}
&.tooltipster-top {
.tooltipster-arrow {
bottom: -2px;
.tooltipster-arrow-uncropped {
.tooltipster-arrow-border {
border-top-color: rgba(0, 0, 0, 0.54);
}
.tooltipster-arrow-background {
border-top-color: transparent;
}
}
}
}
&.tooltipster-bottom {
.tooltipster-arrow {
top: -2px;
.tooltipster-arrow-uncropped {
.tooltipster-arrow-border {
border-bottom-color: rgba(0, 0, 0, 0.54);
}
.tooltipster-arrow-background {
border-bottom-color: transparent;
}
}
}
}
&.tooltipster-left {
.tooltipster-arrow {
right: -2px;
.tooltipster-arrow-uncropped {
.tooltipster-arrow-border {
border-left-color: rgba(0, 0, 0, 0.54);
}
.tooltipster-arrow-background {
border-left-color: transparent;
}
}
}
}
&.tooltipster-right {
.tooltipster-arrow {
left: -2px;
.tooltipster-arrow-uncropped {
.tooltipster-arrow-border {
border-right-color: rgba(0, 0, 0, 0.54);
}
.tooltipster-arrow-background {
border-right-color: transparent;
}
}
}
}
}
.tb-default, .tb-dark {
/*********************************

9
ui-ngx/yarn.lock

@ -2695,11 +2695,18 @@
dependencies:
"@svgdotjs/svg.js" "^3.1.1"
"@svgdotjs/svg.js@^3.1.1", "@svgdotjs/svg.js@^3.2.0":
"@svgdotjs/svg.js@^3.0.16", "@svgdotjs/svg.js@^3.1.1", "@svgdotjs/svg.js@^3.2.0":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@svgdotjs/svg.js/-/svg.js-3.2.0.tgz#6baa8cef6778a93818ac18faa2055222e60aa644"
integrity sha512-Tr8p+QVP7y+QT1GBlq1Tt57IvedVH8zCPoYxdHLX0Oof3a/PqnC/tXAkVufv1JQJfsDHlH/UrjcDfgxSofqSNA==
"@svgdotjs/svg.panzoom.js@^2.1.2":
version "2.1.2"
resolved "https://registry.yarnpkg.com/@svgdotjs/svg.panzoom.js/-/svg.panzoom.js-2.1.2.tgz#50e66a861f7c4f9e3992707f8e62e6e8da5c5223"
integrity sha512-0Nzo2TRlTebW3pzfAPtHx8Ye7Y3kuMEkK7hwVJi0SgQUB/vstjg7fvCJxB++EqsuDEetP0/SC+4CpLMVm6Lh2g==
dependencies:
"@svgdotjs/svg.js" "^3.0.16"
"@tinymce/tinymce-angular@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@tinymce/tinymce-angular/-/tinymce-angular-7.0.0.tgz#010de497d5774a8bdc5d5936bf4fb976adf05f56"

Loading…
Cancel
Save