UI: Add css animations to SCADA symbol API.
This commit is contained in:
parent
f80a62ad11
commit
5be11f439b
@ -15,7 +15,7 @@
|
|||||||
///
|
///
|
||||||
|
|
||||||
import { ValueType } from '@shared/models/constants';
|
import { ValueType } from '@shared/models/constants';
|
||||||
import { Box, Element, Runner, SVG, Svg, Text, Timeline } from '@svgdotjs/svg.js';
|
import { Box, Element, Runner, Style, SVG, Svg, Text, Timeline } from '@svgdotjs/svg.js';
|
||||||
import '@svgdotjs/svg.panzoom.js';
|
import '@svgdotjs/svg.panzoom.js';
|
||||||
import {
|
import {
|
||||||
DataToValueType,
|
DataToValueType,
|
||||||
@ -58,6 +58,7 @@ export interface ScadaSymbolApi {
|
|||||||
enable: (element: Element | Element[]) => void;
|
enable: (element: Element | Element[]) => void;
|
||||||
callAction: (event: Event, behaviorId: string, value?: any, observer?: Partial<Observer<void>>) => void;
|
callAction: (event: Event, behaviorId: string, value?: any, observer?: Partial<Observer<void>>) => void;
|
||||||
setValue: (valueId: string, value: any) => void;
|
setValue: (valueId: string, value: any) => void;
|
||||||
|
cssAnimate: CssScadaSymbolAnimations;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ScadaSymbolContext {
|
export interface ScadaSymbolContext {
|
||||||
@ -621,7 +622,8 @@ export class ScadaSymbolObject {
|
|||||||
disable: this.disableElement.bind(this),
|
disable: this.disableElement.bind(this),
|
||||||
enable: this.enableElement.bind(this),
|
enable: this.enableElement.bind(this),
|
||||||
callAction: this.callAction.bind(this),
|
callAction: this.callAction.bind(this),
|
||||||
setValue: this.setValue.bind(this)
|
setValue: this.setValue.bind(this),
|
||||||
|
cssAnimate: new CssScadaSymbolAnimations(this.svgShape)
|
||||||
},
|
},
|
||||||
tags: {},
|
tags: {},
|
||||||
properties: {},
|
properties: {},
|
||||||
@ -1008,3 +1010,301 @@ export class ScadaSymbolObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scadaSymbolAnimationId = 'scadaSymbolAnimation';
|
||||||
|
|
||||||
|
class CssScadaSymbolAnimations {
|
||||||
|
constructor(private svgShape: Svg) {}
|
||||||
|
|
||||||
|
public rotate(element: Element, rotation: number, duration = 1000, loop = false): CssScadaSymbolAnimation {
|
||||||
|
this.checkOldAnimation(element);
|
||||||
|
return this.setupAnimation(element,
|
||||||
|
new RotateCssScadaSymbolAnimation(this.svgShape, element, loop, rotation || 0)).duration(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public move(element: Element, deltaX: number, deltaY: number, duration = 1000, loop = false): CssScadaSymbolAnimation {
|
||||||
|
this.checkOldAnimation(element);
|
||||||
|
return this.setupAnimation(element,
|
||||||
|
new MoveCssScadaSymbolAnimation(this.svgShape, element, loop, deltaX, deltaY).duration(duration));
|
||||||
|
}
|
||||||
|
|
||||||
|
public attr(element: Element, attrName: string, value: any, duration = 1000, loop = false): CssScadaSymbolAnimation {
|
||||||
|
this.checkOldAnimation(element);
|
||||||
|
return this.setupAnimation(element,
|
||||||
|
new AttrsCssScadaSymbolAnimation(this.svgShape, element, loop, {[attrName]: value}).duration(duration));
|
||||||
|
}
|
||||||
|
|
||||||
|
public attrs(element: Element, attr: any, duration = 1000, loop = false): CssScadaSymbolAnimation {
|
||||||
|
this.checkOldAnimation(element);
|
||||||
|
return this.setupAnimation(element,
|
||||||
|
new AttrsCssScadaSymbolAnimation(this.svgShape, element, loop, attr).duration(duration));
|
||||||
|
}
|
||||||
|
|
||||||
|
public animation(element: Element): CssScadaSymbolAnimation | undefined {
|
||||||
|
return element.remember(scadaSymbolAnimationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private checkOldAnimation(element: Element) {
|
||||||
|
const previousAnimation: CssScadaSymbolAnimation = element.remember(scadaSymbolAnimationId);
|
||||||
|
if (previousAnimation) {
|
||||||
|
previousAnimation.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupAnimation(element: Element, animation: CssScadaSymbolAnimation): CssScadaSymbolAnimation {
|
||||||
|
animation.init();
|
||||||
|
element.remember(scadaSymbolAnimationId, animation);
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ScadaSymbolAnimationKeyframe {
|
||||||
|
stop: string;
|
||||||
|
style: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class CssScadaSymbolAnimation {
|
||||||
|
|
||||||
|
private _animationName: string;
|
||||||
|
private _animationStyle: Style;
|
||||||
|
|
||||||
|
private _running = true;
|
||||||
|
private _speed = 1;
|
||||||
|
private _duration = 1000;
|
||||||
|
private _easing = 'linear';
|
||||||
|
|
||||||
|
protected constructor(protected svgShape: Svg,
|
||||||
|
protected element: Element,
|
||||||
|
protected loop: boolean) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
this.prepareAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public start() {
|
||||||
|
if (!this._running) {
|
||||||
|
this.updateAnimationStyle('animation-play-state', 'running');
|
||||||
|
this._running = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public pause() {
|
||||||
|
if (this._running) {
|
||||||
|
this.updateAnimationStyle('animation-play-state', 'paused');
|
||||||
|
this._running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public running(): boolean {
|
||||||
|
return this._running;
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy() {
|
||||||
|
if (this._animationStyle) {
|
||||||
|
this._animationStyle.remove();
|
||||||
|
this.element.removeClass(this._animationName);
|
||||||
|
this._animationStyle = null;
|
||||||
|
this._animationName = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public duration(duration: number): CssScadaSymbolAnimation {
|
||||||
|
this._duration = duration;
|
||||||
|
this.updateAnimationStyle(this.loop ? 'animation-duration' : 'transition-duration',
|
||||||
|
Math.round(this._duration / this._speed) + 'ms');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public speed(speed: number): CssScadaSymbolAnimation {
|
||||||
|
this._speed = speed;
|
||||||
|
this.updateAnimationStyle(this.loop ? 'animation-duration' : 'transition-duration',
|
||||||
|
Math.round(this._duration / this._speed) + 'ms');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public easing(easing: string): CssScadaSymbolAnimation {
|
||||||
|
this._easing = easing;
|
||||||
|
this.updateAnimationStyle(this.loop ? 'animation-timing-function' : 'transition-timing-function', this._easing);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private prepareAnimation() {
|
||||||
|
this._animationName = 'animation_' + generateElementId();
|
||||||
|
this._animationStyle = this.svgShape.style();
|
||||||
|
let styles: any;
|
||||||
|
if (this.loop) {
|
||||||
|
styles = {
|
||||||
|
'animation-name': this._animationName,
|
||||||
|
'animation-duration': this._duration + 'ms',
|
||||||
|
'animation-timing-function': this._easing,
|
||||||
|
'animation-iteration-count': 'infinite',
|
||||||
|
'animation-fill-mode': 'forwards',
|
||||||
|
'animation-play-state': 'running',
|
||||||
|
...this.animationStyles()
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
styles = {
|
||||||
|
'transition-property': this.transitionProperties(),
|
||||||
|
'transition-duration': this._duration + 'ms',
|
||||||
|
'transition-timing-function': this._easing,
|
||||||
|
...this.animationStyles()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this._animationStyle.rule('.' + this._animationName, styles);
|
||||||
|
|
||||||
|
if (this.loop) {
|
||||||
|
const keyframes = this.animationKeyframes();
|
||||||
|
let keyframesCss = `\n@keyframes ${this._animationName} {\n`;
|
||||||
|
for (const keyframe of keyframes) {
|
||||||
|
let keyframeCss = ` ${keyframe.stop} {\n`;
|
||||||
|
for (const i of Object.keys(keyframe.style)) {
|
||||||
|
keyframeCss += ' ' + i + ':' + keyframe.style[i] + ';\n';
|
||||||
|
}
|
||||||
|
keyframeCss += ' }\n';
|
||||||
|
keyframesCss += keyframeCss;
|
||||||
|
}
|
||||||
|
keyframesCss += '}';
|
||||||
|
this._animationStyle.addText(keyframesCss);
|
||||||
|
}
|
||||||
|
this.element.addClass(this._animationName);
|
||||||
|
if (!this.loop) {
|
||||||
|
this.doTransform();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateAnimationStyle(attrName: string, value: any) {
|
||||||
|
if (this._animationStyle) {
|
||||||
|
const styleText = this._animationStyle.node.innerHTML;
|
||||||
|
const attrValueRegex = new RegExp(`${attrName}:([^;]+);`);
|
||||||
|
this._animationStyle.node.innerHTML = styleText.replace(attrValueRegex, `${attrName}:${value};`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected animationStyles(): any {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract animationKeyframes(): ScadaSymbolAnimationKeyframe[];
|
||||||
|
|
||||||
|
protected abstract transitionProperties(): string;
|
||||||
|
|
||||||
|
protected doTransform() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class RotateCssScadaSymbolAnimation extends CssScadaSymbolAnimation {
|
||||||
|
|
||||||
|
constructor(protected svgShape: Svg,
|
||||||
|
protected element: Element,
|
||||||
|
protected loop: boolean,
|
||||||
|
private rotation: number) {
|
||||||
|
super(svgShape, element, loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected animationStyles(): any {
|
||||||
|
return {
|
||||||
|
'transform-origin': `${this.element.cx()}px ${this.element.cy()}px`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected animationKeyframes(): ScadaSymbolAnimationKeyframe[] {
|
||||||
|
const transform = this.element.transform();
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
stop: '0%',
|
||||||
|
style: {
|
||||||
|
transform: `translate(${transform.translateX}px, ${transform.translateY}px) rotate(${transform.rotate}deg)`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stop: '100%',
|
||||||
|
style: {
|
||||||
|
transform: `translate(${transform.translateX}px, ${transform.translateY}px) rotate(${this.rotation}deg)`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected transitionProperties(): string {
|
||||||
|
return 'transform';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doTransform() {
|
||||||
|
const transform = this.element.transform();
|
||||||
|
this.element.attr({transform: `translate(${transform.translateX} ${transform.translateY}) rotate(${this.rotation})`});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class MoveCssScadaSymbolAnimation extends CssScadaSymbolAnimation {
|
||||||
|
|
||||||
|
constructor(protected svgShape: Svg,
|
||||||
|
protected element: Element,
|
||||||
|
protected loop: boolean,
|
||||||
|
private deltaX: number,
|
||||||
|
private deltaY: number) {
|
||||||
|
super(svgShape, element, loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected animationStyles(): any {
|
||||||
|
return {
|
||||||
|
'transform-origin': `${this.element.cx()}px ${this.element.cy()}px`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected animationKeyframes(): ScadaSymbolAnimationKeyframe[] {
|
||||||
|
const transform = this.element.transform();
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
stop: '0%',
|
||||||
|
style: {
|
||||||
|
transform: `translate(${transform.translateX}px, ${transform.translateY}px)`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stop: '100%',
|
||||||
|
style: {
|
||||||
|
transform: `translate(${transform.translateX+this.deltaX}px, ${transform.translateY+this.deltaY}px)`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected transitionProperties(): string {
|
||||||
|
return 'transform';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doTransform() {
|
||||||
|
this.element.relative(this.deltaX, this.deltaY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class AttrsCssScadaSymbolAnimation extends CssScadaSymbolAnimation {
|
||||||
|
|
||||||
|
constructor(protected svgShape: Svg,
|
||||||
|
protected element: Element,
|
||||||
|
protected loop: boolean,
|
||||||
|
private attr: any) {
|
||||||
|
super(svgShape, element, loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected animationStyles(): any {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected animationKeyframes(): ScadaSymbolAnimationKeyframe[] {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected transitionProperties(): string {
|
||||||
|
return Object.keys(this.attr).join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected doTransform() {
|
||||||
|
this.element.attr(this.attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user