@syncfusion/ej2-lineargauge
Version:
Essential JS 2 LinearGauge Components
272 lines (265 loc) • 17 kB
text/typescript
import { Animation, AnimationOptions, isNullOrUndefined, animationMode } from '@syncfusion/ej2-base';
import { LinearGauge } from '../../linear-gauge';
import { Axis, Pointer } from './axis';
import { animationComplete } from '../model/constant';
import { Size, valueToCoefficient, PathOption, TextOption, Rect } from '../utils/helper';
import { calculateShapes, calculateTextPosition, getBox, VisibleRange } from '../utils/helper';
/**
* To handle the animation for gauge
*
* @private
*/
export class Animations {
public gauge: LinearGauge;
constructor(gauge: LinearGauge) {
this.gauge = gauge;
}
/**
* To do the marker pointer animation.
*
* @param element - Specifies the element of the marker pointer to which animation must be propagated.
* @param axis - Specifies the axis in which the marker pointer is available to which animation must be propagated.
* @param pointer - Specifies the pointer to which the animation must be propagated.
*/
public performMarkerAnimation(element: Element, axis: Axis, pointer: Pointer): void {
const markerElement: HTMLElement = <HTMLElement>element;
let options: PathOption; let textOptions: TextOption; let timeStamp: number;
const range: VisibleRange = axis.visibleRange;
const rectHeight: number = (this.gauge.orientation === 'Vertical') ? axis.lineBounds.height : axis.lineBounds.width;
const rectY: number = (this.gauge.orientation === 'Vertical') ? axis.lineBounds.y : axis.lineBounds.x;
if (this.gauge.orientation === 'Vertical') {
pointer.bounds.y = (valueToCoefficient(pointer.currentValue, axis, this.gauge.orientation, range) * rectHeight) + rectY;
} else {
pointer.bounds.x = (valueToCoefficient(pointer.currentValue, axis, this.gauge.orientation, range) * rectHeight) + rectY;
}
options = new PathOption(markerElement.id, null, null, null);
options = calculateShapes(
pointer.bounds, pointer.markerType, new Size(pointer.width, pointer.height),
pointer.imageUrl, options, this.gauge.orientation, axis, pointer);
if (pointer.markerType === 'Text') {
textOptions = new TextOption(markerElement.id, 0, 0, 'middle', pointer.text, null, 'auto');
textOptions = calculateTextPosition(pointer.bounds, pointer.markerType,
textOptions, this.gauge.orientation, axis, pointer);
}
let currentValue: number;
let start: number = typeof(pointer.startValue) === 'string' ? parseInt(pointer.startValue, 10) : pointer.startValue;
const end: number = pointer.currentValue;
start = (start === end) ? range.min : start;
const val: number = Math.abs(start - end);
const currentPath: string = options.d;
const cx: number = options['cx'];
const cy: number = options['cy'];
const x: number = pointer.markerType === 'Text' ? textOptions['x'] : options['x'];
const y: number = pointer.markerType === 'Text' ? textOptions['y'] : options['y'];
new Animation({}).animate(markerElement, {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
name: 'Linear' as any,
duration: (animationMode === 'Enable' && ((pointer.animationDuration === 0 && !this.gauge.allowLoadingAnimation) ||
this.gauge.animationDuration === 0)) ? 1000 : (this.gauge.allowLoadingAnimation && pointer.animationDuration === 0 ?
(this.gauge.animationDuration / this.gauge.splitUpCount) : pointer.animationDuration),
progress: (args: AnimationOptions): void => {
if (args.timeStamp >= args.delay) {
timeStamp = ((args.timeStamp - args.delay) / args.duration);
currentValue = (start < end) ? start + (timeStamp * val) : start - (timeStamp * val);
if (this.gauge.orientation === 'Vertical') {
pointer.bounds.y = (valueToCoefficient(currentValue, axis, this.gauge.orientation, range) *
rectHeight) + rectY;
options = calculateShapes(
pointer.bounds, pointer.markerType, new Size(pointer.width, pointer.height),
pointer.imageUrl, options, this.gauge.orientation, axis, pointer);
if (pointer.markerType === 'Text') {
textOptions = calculateTextPosition(pointer.bounds, pointer.markerType,
textOptions, this.gauge.orientation, axis, pointer);
}
if (!isNullOrUndefined(options['r'])) {
markerElement.setAttribute('cy', options['cy'].toString());
}
else if (!isNullOrUndefined(pointer.markerType === 'Text' ? textOptions['y'] : options['y'])) {
markerElement.setAttribute('y', pointer.markerType === 'Text' ? textOptions['y'] : options['y'].toString());
}
else {
markerElement.setAttribute('d', options.d);
}
markerElement.style.visibility = 'visible';
} else {
pointer.bounds.x = (valueToCoefficient(currentValue, axis, this.gauge.orientation, range) *
rectHeight) + rectY;
options = calculateShapes(
pointer.bounds, pointer.markerType, new Size(pointer.width, pointer.height),
pointer.imageUrl, options, this.gauge.orientation, axis, pointer);
if (pointer.markerType === 'Text') {
textOptions = calculateTextPosition(pointer.bounds, pointer.markerType,
textOptions, this.gauge.orientation, axis, pointer);
}
if (!isNullOrUndefined(options['r'])) {
markerElement.setAttribute('cx', options['cx'].toString());
}
else if (!isNullOrUndefined(pointer.markerType === 'Text' ? textOptions['x'] : options['x'])) {
markerElement.setAttribute('x', pointer.markerType === 'Text' ? textOptions['x'] : options['x'].toString());
}
else {
markerElement.setAttribute('d', options.d);
}
markerElement.style.visibility = 'visible';
}
}
},
end: () => {
if (!isNullOrUndefined(cy)) {
markerElement.setAttribute('cy', cy.toString());
markerElement.setAttribute('cx', cx.toString());
}
else if (!isNullOrUndefined(y)) {
markerElement.setAttribute('y', y.toString());
markerElement.setAttribute('x', x.toString());
}
else {
markerElement.setAttribute('d', currentPath);
}
markerElement.style.visibility = 'visible';
pointer.isPointerAnimation = false;
pointer.animationComplete = true;
pointer.startValue = pointer.value = pointer.currentValue;
this.gauge.trigger(animationComplete, { axis: axis, pointer: pointer });
if (this.gauge.allowLoadingAnimation) {
if (!isNullOrUndefined(this.gauge.annotationsModule) && (this.gauge.annotations.length > 0 && (this.gauge.annotations[0].content !== '' || this.gauge.annotations.length > 1))) {
const element: Element = document.getElementById(this.gauge.element.id + '_AnnotationsGroup');
this.gauge.annotationsModule.annotationAnimate(element, this.gauge);
} else {
this.gauge.allowLoadingAnimation = false;
this.gauge.isOverAllAnimationComplete = true;
}
}
}
});
}
/**
* Perform the bar pointer animation
*
* @param element
* @param axis
* @param pointer
*/
public performBarAnimation(element: Element, axis: Axis, pointer: Pointer): void {
const radix: number = 10; let timeStamp: number; let value2: number; let value1: number;
let currentValue: number;
let clipHeight: string; let clipY: string; let clipX: string; let clipVal: number;
let clipWidth: string; let currentHeight: number; let clipElement: HTMLElement;
const range: VisibleRange = axis.visibleRange;
const pointerElement: HTMLElement = <HTMLElement>element;
const lineHeight: number = (this.gauge.orientation === 'Vertical') ? axis.lineBounds.height : axis.lineBounds.width;
const lineY: number = (this.gauge.orientation === 'Vertical') ? axis.lineBounds.y : axis.lineBounds.x;
let start: number = typeof(pointer.startValue) === 'string' ? parseInt(pointer.startValue, 10) : pointer.startValue;
const end: number = pointer.currentValue;
start = (start === end) ? range.min : start;
let path: string = ''; let currentPath: string = '';
const tagName: string = pointerElement.tagName;
const val: number = Math.abs(start - end);
const pointerValue: number = (valueToCoefficient(end, axis, this.gauge.orientation, range) * lineHeight) + lineY;
const startPointerVal: number = (valueToCoefficient(range.min, axis, this.gauge.orientation, range) *
lineHeight) + lineY;
const rectY: number = (this.gauge.orientation === 'Vertical') ? !axis.isInversed ? pointerValue : startPointerVal :
axis.isInversed ? pointerValue : startPointerVal;
const rectHeight: number = Math.abs(startPointerVal - pointerValue);
if (this.gauge.container.type === 'Thermometer' && start === 0 && this.gauge.container.width > 0) {
if (end === axis.minimum) {
(element as HTMLElement).style.visibility = 'visible';
} else {
clipElement = <HTMLElement>pointerElement.parentElement.childNodes[1].childNodes[0].childNodes[0];
if (this.gauge.orientation === 'Vertical') {
clipY = clipElement.getAttribute('y');
clipHeight = clipElement.getAttribute('height');
clipVal = parseInt(clipY, radix) + parseInt(clipHeight, radix);
clipElement.setAttribute('y', clipVal.toString());
} else {
clipX = clipElement.getAttribute('x');
clipWidth = clipElement.getAttribute('width');
clipVal = parseInt(clipX, radix) + parseInt(clipWidth, radix);
clipElement.setAttribute('width', '0');
}
}
}
path = pointer.value === axis.minimum && this.gauge.container.type === 'RoundedRectangle' ? '' : getBox(
pointer.bounds, this.gauge.container.type, this.gauge.orientation,
new Size(pointer.bounds.width, pointer.bounds.height), 'bar', this.gauge.container.width, axis, pointer.roundedCornerRadius);
let animatedPointerWidth: number = pointer.bounds.width;
let animatedPointerHeight: number = pointer.bounds.height;
new Animation({}).animate(pointerElement, {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
name: 'Linear' as any,
duration: (animationMode === 'Enable' && ((pointer.animationDuration === 0 && !this.gauge.allowLoadingAnimation) ||
this.gauge.animationDuration === 0)) ? 1000 : (this.gauge.allowLoadingAnimation && pointer.animationDuration === 0 ?
(this.gauge.animationDuration / this.gauge.splitUpCount) : pointer.animationDuration),
progress: (animate: AnimationOptions): void => {
if (animate.timeStamp >= animate.delay) {
timeStamp = ((animate.timeStamp - animate.delay) / animate.duration);
currentValue = (start < end) ? start + (timeStamp * val) : start - (timeStamp * val);
value2 = (valueToCoefficient(currentValue, axis, this.gauge.orientation, range) * lineHeight) + lineY;
value1 = (valueToCoefficient(range.min, axis, this.gauge.orientation, range) * lineHeight) + lineY;
currentHeight = Math.abs(value2 - value1);
if (this.gauge.orientation === 'Vertical') {
pointer.bounds.y = (!axis.isInversed) ? value2 : value1;
animatedPointerHeight = currentHeight;
} else {
pointer.bounds.x = (axis.isInversed) ? value2 : value1;
animatedPointerWidth = currentHeight;
}
if (tagName === 'path') {
if (start === 0 && this.gauge.container.type === 'Thermometer') {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
(this.gauge.orientation === 'Vertical') ?
clipElement.setAttribute('y', (clipVal - (timeStamp * parseInt(clipHeight, radix))).toString()) :
clipElement.setAttribute('width', (timeStamp * parseInt(clipWidth, radix)).toString());
}
currentPath = pointer.value === axis.minimum && this.gauge.container.type === 'RoundedRectangle' ? '' : getBox(
new Rect(pointer.bounds.x, pointer.bounds.y, animatedPointerWidth, animatedPointerHeight),
this.gauge.container.type,
this.gauge.orientation, new Size(animatedPointerWidth, animatedPointerHeight), 'bar',
this.gauge.container.width, axis, pointer.roundedCornerRadius);
pointerElement.setAttribute('d', currentPath);
pointerElement.style.visibility = 'visible';
} else {
if (this.gauge.orientation === 'Vertical') {
pointerElement.setAttribute('y', pointer.bounds.y.toString());
pointerElement.setAttribute('height', animatedPointerHeight.toString());
} else {
pointerElement.setAttribute('x', pointer.bounds.x.toString());
pointerElement.setAttribute('width', animatedPointerWidth.toString());
}
pointerElement.style.visibility = 'visible';
}
}
},
end: () => {
if (tagName === 'path') {
if (start === 0 && this.gauge.container.type === 'Thermometer') {
pointerElement.parentElement.children[1].remove();
} else {
pointerElement.setAttribute('d', path);
}
} else {
if (this.gauge.orientation === 'Vertical') {
pointerElement.setAttribute('y', rectY.toString());
pointerElement.setAttribute('height', rectHeight.toString());
} else {
pointerElement.setAttribute('x', rectY.toString());
pointerElement.setAttribute('width', rectHeight.toString());
}
}
pointerElement.style.visibility = 'visible';
pointer.isPointerAnimation = false;
pointer.startValue = pointer.value = pointer.currentValue;
this.gauge.trigger(animationComplete, { axis: axis, pointer: pointer });
if (this.gauge.allowLoadingAnimation) {
if (!isNullOrUndefined(this.gauge.annotationsModule) && (this.gauge.annotations.length > 0 && (this.gauge.annotations[0].content !== '' || this.gauge.annotations.length > 1))) {
const element: Element = document.getElementById(this.gauge.element.id + '_AnnotationsGroup');
this.gauge.annotationsModule.annotationAnimate(element, this.gauge);
} else {
this.gauge.allowLoadingAnimation = false;
this.gauge.isOverAllAnimationComplete = true;
}
}
}
});
}
}