@syncfusion/ej2-circulargauge
Version:
Essential JS 2 CircularGauge Components
985 lines (937 loc) • 46.4 kB
text/typescript
/* eslint-disable max-len */
/**
* Specifies Circular-Gauge Common Helper methods
*/
import { compile as templateComplier, isNullOrUndefined, remove, createElement, merge } from '@syncfusion/ej2-base';
import { CircularGauge } from '../circular-gauge';
import { Range, Axis } from '../axes/axis';
import { IVisiblePointer } from '../model/interface';
import { FontModel, BorderModel } from '../model/base-model';
import { SvgRenderer } from '@syncfusion/ej2-svg-base';
/**
* Function to measure the height and width of the text.
*
* @param {string} text - Specifies the text.
* @param {FontModel} font - Specifies the font.
* @returns {Size} - Returns the size of the text.
* @private
*/
export function measureText(text: string, font: FontModel): Size {
let htmlObject: HTMLElement = document.getElementById('gauge-measuretext');
if (htmlObject === null) {
htmlObject = createElement('text', { id: 'gauge-measuretext' });
document.body.appendChild(htmlObject);
}
const style: string = 'position: absolute; visibility: hidden;' +
';left: 0px; top: -100px; white-space: nowrap;' + getFontStyle(font);
htmlObject.innerText = text;
htmlObject.style.cssText = style;
return new Size(htmlObject.clientWidth, htmlObject.clientHeight);
}
/**
* Function to find number from string
*
* @param {string} value - Specifies the value.
* @param {number} maxDimension - Specifies the maximum dimension.
* @returns {number} - Returns the number.
* @private
*/
export function toPixel(value: string, maxDimension: number): number {
return value.indexOf('%') !== -1 ? (maxDimension / 100) * parseInt(value, 10) : parseInt(value, 10);
}
/**
* Function to get the style from FontModel.
*
* @param {FontModel} font - Specifies the font.
* @returns {string} - Returns the string.
* @private
*/
export function getFontStyle(font: FontModel): string {
let style: string = '';
style = 'font-size:' + font.size +
'; font-style:' + font.fontStyle + '; font-weight:' + font.fontWeight +
'; font-family:' + font.fontFamily + ';opacity:' + font.opacity +
'; color:' + font.color + ';';
return style;
}
/**
* Function to create the text element.
*
* @param {TextOption} options - Specifies the options.
* @param {FontModel} font - Specifies the font.
* @param {string} color - Specifies the color.
* @param {HTMLElement | Element} parent - Specifies the html element.
* @param {string} styles - Specifies the style.
* @returns {Element} - Returns the element.
* @private
*/
export function textElement(options: TextOption, font: FontModel, color: string, parent: HTMLElement | Element, styles?: string): Element {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let renderOptions: any = {};
const renderer: SvgRenderer = new SvgRenderer('');
const style: string = styles + ' font-size:' + font.size + '; font-style:' + font.fontStyle +
' ; font-weight:' + font.fontWeight + '; font-family:' + font.fontFamily + ';';
renderOptions = {
'id': options.id,
'x': options.x,
'y': options.y,
'fill': color,
'text-anchor': options.anchor,
'transform': options.transform,
'opacity': font.opacity,
'dominant-baseline': options.baseLine,
'style': style
};
const htmlObject: Element = renderer.createText(renderOptions, options.text);
parent.appendChild(htmlObject);
return htmlObject;
}
/**
* Function to append the path to the element.
*
* @param {PathOption} options - Specifies the options.
* @param {Element} element - Specifies the element.
* @param {CircularGauge} gauge - Specifies the gauge.
* @param {string} functionName - Specifies the function name.
* @returns {Element} - Returns the element.
* @private
*/
export function appendPath(options: PathOption, element: Element, gauge: CircularGauge, functionName?: string): Element {
functionName = functionName ? functionName : 'Path';
const htmlObject: HTMLElement = gauge.renderer['draw' + functionName](options) as HTMLElement;
htmlObject.setAttribute('transform', options.transform);
htmlObject.style.cssText = options.style;
element.appendChild(htmlObject);
return htmlObject;
}
/**
* Function to check whether it's a complete circle for circular gauge.
*
* @param {number} startAngle - Specifies the startAngle.
* @param {number} endAngle - Specifies the endAngle.
* @returns {boolean} Returns the boolean value.
* @private
*/
export function isCompleteAngle(startAngle: number, endAngle: number): boolean {
let totalAngle: number = endAngle - startAngle;
totalAngle = totalAngle <= 0 ? (totalAngle + 360) : totalAngle;
return Math.floor(totalAngle / 360) !== 0;
}
/**
* Function to get the degree for circular gauge.
*
* @param {number} startAngle - Specifies the startAngle.
* @param {number} endAngle - Specifies the endAngle.
* @returns {number} - Returns the number.
* @private
*/
export function getDegree(startAngle: number, endAngle: number): number {
const degree: number = endAngle - startAngle;
return degree < 0 ? (degree + 360) : degree;
}
/**
* Function to get the angle from value for circular gauge.
*
* @param {number} value - Specifies the value.
* @param {number} maximumValue - Specifies the maximumValue.
* @param {number} minimumValue - Specifies the minimumValue.
* @param {number} startAngle - Specifies the startAngle.
* @param {number} endAngle - Specifies the endAngle.
* @param {boolean} isClockWise - Specifies the isClockWise.
* @returns {number} - Returns the number.
* @private
*/
export function getAngleFromValue(
value: number, maximumValue: number, minimumValue: number, startAngle: number, endAngle: number, isClockWise: boolean
): number {
let angle: number;
endAngle -= isCompleteAngle(startAngle, endAngle) ? 0.0001 : 0;
startAngle -= 90; endAngle -= 90;
if (isClockWise) {
angle = ((value - minimumValue) * (getDegree(startAngle, endAngle) / (maximumValue - minimumValue))) + startAngle;
} else {
angle = endAngle - ((value - minimumValue) * (getDegree(startAngle, endAngle) / (maximumValue - minimumValue)));
angle = angle < 0 ? 360 + angle : angle;
}
angle = Math.round(angle) >= 360 ? (angle - 360) : Math.round(angle) < 0 ? (360 + angle) : angle;
return angle;
}
/**
* Function to get angle from location for circular gauge.
*
* @param {GaugeLocation} center - Specifies the center.
* @param {GaugeLocation} point - Specifies the point.
* @returns {number} - Returns the number.
* @private
*/
export function getAngleFromLocation(center: GaugeLocation, point: GaugeLocation): number {
let angle: number = Math.atan2((point.y - center.y), (point.x - center.x));
angle = Math.round((angle < 0 ? (6.283 + angle) : angle) * (180 / Math.PI)) - 270;
angle += angle < 0 ? 360 : 0;
return angle;
}
/**
* Function to get the location from angle for circular gauge.
*
* @param {number} degree - Specifies the degree.
* @param {number} radius - Specifies the radius.
* @param {GaugeLocation} center - Specifies the center.
* @returns {GaugeLocation} - Returns the gauge location.
* @private
*/
export function getLocationFromAngle(degree: number, radius: number, center: GaugeLocation): GaugeLocation {
const radian: number = (degree * Math.PI) / 180;
return new GaugeLocation(
Math.cos(radian) * radius + center.x,
Math.sin(radian) * radius + center.y
);
}
/**
* Function to get the path direction of the circular gauge.
*
* @param {GaugeLocation} center - Specifies the center.
* @param {number} start - Specifies the start.
* @param {number} end - Specifies the end.
* @param {number} radius - Specifies the radius.
* @param {number} startWidth - Specifies the startWidth.
* @param {number} endWidth - Specifies the endWidth.
* @param {Range} range - Specifies the range.
* @param {Axis} axis - Specifies the axis.
* @returns {string} - Returns the string.
* @private
*/
export function getPathArc(
center: GaugeLocation, start: number, end: number, radius: number,
startWidth?: number, endWidth?: number, range?: Range, axis?: Axis
): string {
if (isNullOrUndefined(range) || (range.start !== range.end)) {
end -= isCompleteAngle(start, end) ? 0.0001 : 0;
}
const degree: number = getDegree(start, end);
const startRadius: number = !isNullOrUndefined(range) ? (range.position === 'Outside' && !range.isLinearCircularGradient
? radius + startWidth : range.position === 'Cross'
&& axis.direction === 'AntiClockWise' ? radius - (endWidth + startWidth) / 2 : radius - startWidth) : radius - startWidth;
const endRadius: number = !isNullOrUndefined(range) ? (range.position === 'Outside'
&& !range.isLinearCircularGradient ? radius + endWidth : range.position === 'Cross' &&
axis.direction === 'ClockWise' ? radius - (endWidth + startWidth) / 2 : radius - endWidth) : radius - endWidth;
const arcRadius: number = !isNullOrUndefined(range) ? (range.position === 'Outside' && !range.isLinearCircularGradient
? radius + ((startWidth + endWidth) / 2) :
range.position === 'Cross' ? (radius - ((startWidth + endWidth) / 4) - (axis.direction === 'ClockWise' ? startWidth : endWidth)
/ 2) : radius - ((startWidth + endWidth) / 2)) : radius - ((startWidth + endWidth) / 2);
const insideArcRadius: number = !isNullOrUndefined(range) && range.position === 'Cross' ?
radius + ((startWidth + endWidth) / 4)
- (axis.direction === 'ClockWise' ? startWidth : endWidth) / 2 : radius;
let insideEndRadius: number = !isNullOrUndefined(range) && range.position === 'Cross' && axis.direction === 'ClockWise' ?
radius - ((startWidth - endWidth) / 2) : radius;
const insideStartRadius: number = !isNullOrUndefined(range) && range.position === 'Cross' && axis.direction === 'AntiClockWise' ?
radius + ((startWidth - endWidth) / 2) : radius;
if (startWidth !== undefined && endWidth !== undefined) {
insideEndRadius = range.position === 'Cross' ? (degree > 325 ? insideStartRadius : insideEndRadius) : insideEndRadius;
return getRangePath(
getLocationFromAngle(start, insideStartRadius, center),
getLocationFromAngle(end, insideEndRadius, center),
getLocationFromAngle(start, startRadius, center),
getLocationFromAngle(end, endRadius, center),
insideArcRadius, startRadius, endRadius, arcRadius,
(degree < 180) ? 0 : 1, center, degree, range, axis
);
} else {
return getCirclePath(
getLocationFromAngle(start, radius, center),
getLocationFromAngle(end, radius, center), radius, (degree < 180) ? 0 : 1
);
}
}
/**
* Function to get the range path arc direction of the circular gauge.
*
* @param {GaugeLocation} start - Specifies the start.
* @param {GaugeLocation} end - Specifies the end.
* @param {number} radius - Specifies the radius.
* @param {number} arcStartOne - Specifies the arcStartOne.
* @param {number} arcEndOne - Specifies the arcEndOne.
* @param {number} arcStartTwo - Specifies the arcStartTwo.
* @param {number} arcEndTwo - Specifies the arcEndTwo.
* @param {number} clockWise - Specifies the clockWise.
* @param {GaugeLocation} innerStart - Specifies the innerStart.
* @param {GaugeLocation} innerEnd - Specifies the innerEnd.
* @param {GaugeLocation} pointPosition - Specifies the pointPosition.
* @returns {string} - Returns the string.
* @private
*/
export function arcPath(
start: GaugeLocation, end: GaugeLocation, radius: number, arcStartOne: number,
arcEndOne: number, arcStartTwo: number, arcEndTwo: number,
clockWise: number, innerStart: GaugeLocation, innerEnd: GaugeLocation,
pointPosition: GaugeLocation
): string {
return 'M ' + start.x + ' ' + start.y + ' A ' + radius + ' ' + radius + ' 0 ' +
clockWise + ' 1 ' + end.x + ' ' + end.y + ' L ' + innerEnd.x + ' ' + innerEnd.y +
' A ' + arcStartOne + ' ' + arcEndOne + ' 0 ' + clockWise + ' 0 ' + pointPosition.x
+ ' ' + pointPosition.y + ' ' + ' A ' + arcStartTwo + ' ' + arcEndTwo
+ ' 0 ' + clockWise + ' 0 ' + innerStart.x + ' ' + innerStart.y + ' Z ';
}
/**
* Function to get the range path arc direction of the circular gauge.
*
* @param {GaugeLocation} start - Specifies the start.
* @param {GaugeLocation} end - Specifies the end.
* @param {number} radius - Specifies the radius.
* @param {GaugeLocation} outerOldEnd - Specifies the outerOldEnd.
* @param {GaugeLocation} innerOldEnd - Specifies the innerOldEnd.
* @param {number} arcStartOne - Specifies the arcStartOne.
* @param {number} arcEndOne - Specifies the arcEndOne.
* @param {number} arcStartTwo - Specifies the arcStartTwo.
* @param {number} arcEndTwo - Specifies the arcEndTwo.
* @param {number} clockWise - Specifies the clockWise.
* @param {GaugeLocation} innerStart - Specifies the innerStart.
* @param {GaugeLocation} innerEnd - Specifies the innerEnd.
* @param {GaugeLocation} innerOldStart - Specifies the innerOldStart.
* @param {GaugeLocation} outerOldStart - Specifies the outerOldStart.
* @param {GaugeLocation} pointPosition - Specifies the pointPosition.
* @returns {string} - Returns the string.
* @private
*/
export function arcRoundedPath(
start: GaugeLocation, end: GaugeLocation, radius: number, outerOldEnd: GaugeLocation, innerOldEnd: GaugeLocation,
arcStartOne: number, arcEndOne: number, arcStartTwo: number, arcEndTwo: number,
clockWise: number, innerStart: GaugeLocation, innerEnd: GaugeLocation, innerOldStart: GaugeLocation,
outerOldStart: GaugeLocation, pointPosition: GaugeLocation
): string {
const roundedPath: string = 'M ' + start.x + ' ' + start.y + ' A ' + radius + ' ' + radius + ' 0 ' +
clockWise + ' 1 ' + end.x + ' ' + end.y + ' C ' + outerOldEnd.x + ' ' + outerOldEnd.y + ' ' + innerOldEnd.x + ' ' +
innerOldEnd.y + ' ' + innerEnd.x + ' ' + innerEnd.y;
if (isNullOrUndefined(arcStartTwo) && isNullOrUndefined(arcEndTwo)) {
return roundedPath + ' A ' + arcStartOne + ' ' + arcEndOne + ' 0 ' + clockWise + ' 0 ' + innerStart.x + ' '
+ innerStart.y + ' C ' + innerOldStart.x + ' ' + innerOldStart.y + ' ' + outerOldStart.x + ' ' +
outerOldStart.y + ' ' + start.x + ' ' + start.y + ' Z';
} else {
return roundedPath + ' A ' + arcStartOne + ' ' + arcEndOne + ' 0 ' + clockWise + ' 0 '
+ pointPosition.x + ' ' + pointPosition.y + ' ' + ' A ' + arcStartTwo + ' ' + arcEndTwo + ' 0 ' + clockWise + ' 0 '
+ innerStart.x + ' ' + innerStart.y + ' C ' + innerOldStart.x + ' ' + innerOldStart.y + ' ' + outerOldStart.x + ' ' +
outerOldStart.y + ' ' + start.x + ' ' + start.y + ' Z';
}
}
/**
* Function to get the range path direction for different start and end width of the circular gauge.
*
* @param {GaugeLocation} start - Specifies the options.
* @param {GaugeLocation} end - Specifies the end.
* @param {GaugeLocation} innerStart - Specifies the innerStart.
* @param {GaugeLocation} innerEnd - Specifies the innerEnd.
* @param {number} radius - Specifies the radius.
* @param {number} startRadius - Specifies the startRadius.
* @param {number} endRadius - Specifies the endRadius.
* @param {number} clockWise - Specifies the clockWise.
* @returns {string} - Returns the string.
* @private
*/
export function arcWidthPath(
start: GaugeLocation, end: GaugeLocation,
innerStart: GaugeLocation, innerEnd: GaugeLocation,
radius: number, startRadius: number,
endRadius: number, clockWise: number
): string {
return 'M ' + start.x + ' ' + start.y +
' A ' + radius + ' ' + radius + ' 0 ' +
clockWise + ' 1 ' + end.x + ' ' + end.y +
' L ' + innerEnd.x + ' ' + innerEnd.y +
' A ' + endRadius + ' ' + startRadius + ' 0 ' +
clockWise + ' 0 ' + innerStart.x + ' ' + innerStart.y + ' Z';
}
/**
* Function to get the range path direction of the circular gauge.
*
* @param {GaugeLocation} start - Specifies the start values.
* @param {GaugeLocation} end - Specifies the end values.
* @param {GaugeLocation} innerStart - Specifies the innerStart values.
* @param {GaugeLocation} innerEnd - Specifies the innerEnd values.
* @param {number} radius - Specifies the radius value.
* @param {number} startRadius - Specifies the startRadius value.
* @param {number} endRadius - Specifies the endRadius value.
* @param {number} arcRadius - Specifies the arcRadius value.
* @param {number} clockWise - Specifies the clockWise value.
* @param {GaugeLocation} center - Specifies the center value.
* @param {number} degree - Specifies the degree value.
* @param {Range} range - Specifies the range value.
* @param {Axis} axis - Specifies the axis value.
* @returns {string} - Returns the string value.
* @private
*/
export function getRangePath(
start: GaugeLocation, end: GaugeLocation,
innerStart: GaugeLocation, innerEnd: GaugeLocation, radius: number, startRadius: number, endRadius: number,
arcRadius: number, clockWise: number, center: GaugeLocation, degree: number,
range?: Range, axis?: Axis
): string {
const startWidth: number = range.startWidth as number;
const endWidth: number = range.endWidth as number;
const widthDifference: number = Math.abs(startWidth - endWidth);
let endArc: number; let startArc: number;
if (startWidth > endWidth && degree <= 260 && range.position !== 'Cross' && range.position !== 'Outside') {
endArc = (endRadius + (axis.direction === 'ClockWise' ? -(widthDifference / 2) : (widthDifference / 2)));
startArc = (startRadius + (axis.direction === 'ClockWise' ? (widthDifference / 2) : -(widthDifference / 2)));
return arcWidthPath(start, end, innerStart, innerEnd, radius, startArc, endArc, clockWise);
} else if (endWidth > startWidth && degree <= 260 && range.position !== 'Cross' && range.position !== 'Outside') {
endArc = (startRadius + (axis.direction === 'ClockWise' ? -(widthDifference / 2) : (widthDifference / 2)));
startArc = (endRadius + (axis.direction === 'ClockWise' ? (widthDifference / 2) : -(widthDifference / 2)));
return arcWidthPath(start, end, innerStart, innerEnd, radius, startArc, endArc, clockWise);
} else if ((endWidth === startWidth) && (axis.startAngle !== 0 || axis.endAngle !== 0)) {
return arcWidthPath(start, end, innerStart, innerEnd, radius, startRadius, endRadius, clockWise);
} else if ((degree > 260) || (!range.isLinearCircularGradient && axis.startAngle === 0 && axis.endAngle === 0)) {
if (range.roundedCornerRadius <= 0 && range.startWidth === range.endWidth) {
return arcWidthPath(start, end, innerStart, innerEnd, radius, startRadius, endRadius, clockWise);
} else {
return arcWidthPathCalculation(start, end, innerStart, innerEnd, radius, startRadius, endRadius, arcRadius, clockWise,
center, null, null, null, null,
startWidth, endWidth, degree, range, axis
);
}
} else {
if (range.position === 'Cross' || range.position === 'Outside') {
return arcWidthPath(start, end, innerStart, innerEnd, radius, arcRadius, arcRadius, clockWise);
} else {
return arcWidthPath(start, end, innerStart, innerEnd, radius, startRadius, endRadius, clockWise);
}
}
}
/**
* Function to get start and end width range path calculation to the circular gauge.
*
* @param {GaugeLocation} start - Specifies the start value.
* @param {GaugeLocation} end - Specifies the end value.
* @param {GaugeLocation} innerStart - Specifies the innerStart value.
* @param {GaugeLocation} innerEnd - Specifies the innerEnd value.
* @param {number} radius - Specifies the radius value.
* @param {number} startRadius - Specifies the startRadius value.
* @param {number} endRadius - Specifies the endRadius value.
* @param {number} arcRadius - Specifies the arcRadius value.
* @param {number} clockWise - Specifies the clockWise value.
* @param {GaugeLocation} center - Specifies the center value.
* @param {GaugeLocation} outerOldEnd - Specifies the outerOldEnd value.
* @param {GaugeLocation} innerOldEnd - Specifies the innerOldEnd value.
* @param {GaugeLocation} outerOldStart - Specifies the outerOldStart value.
* @param {GaugeLocation} innerOldStart - Specifies the innerOldStart value.
* @param {number} startWidth - Specifies the startWidth value.
* @param {number} endWidth - Specifies the endWidth value.
* @param {number} degree - Specifies the degree value.
* @param {Range} range - Specifies the range value.
* @param {Axis} axis - Specifies the axis value.
* @returns {string} - Returns the svg path.
* @private
*/
export function arcWidthPathCalculation(
start: GaugeLocation, end: GaugeLocation, innerStart: GaugeLocation, innerEnd: GaugeLocation,
radius: number, startRadius: number, endRadius: number, arcRadius: number, clockWise: number, center: GaugeLocation,
outerOldEnd: GaugeLocation, innerOldEnd: GaugeLocation, outerOldStart: GaugeLocation,
innerOldStart: GaugeLocation, startWidth: number, endWidth: number, degree: number, range?: Range, axis?: Axis
): string {
if (!isNullOrUndefined(range)) {
let arcStartOne: number; let arcEndOne: number;
let widthDifference: number = Math.abs(startWidth - endWidth); let arcStartTwo: number; let arcEndTwo: number;
const startValueToAngle: number = getAngleFromValue(((range.start + range.end) / 2), axis.maximum, axis.minimum, axis.startAngle,
axis.endAngle, axis.direction === 'ClockWise');
const pointPosition: GaugeLocation = (startWidth < ((endWidth))) ?
getLocationFromAngle(startValueToAngle, endRadius, center) : getLocationFromAngle(startValueToAngle, startRadius, center);
const endDistance: number = Math.sqrt((Math.pow((innerEnd.x - pointPosition.x), 2)) + (Math.pow((innerEnd.y - pointPosition.y), 2)));
const endRadii: number = endDistance / 2;
const centerStartDistance: number = Math.sqrt((Math.pow((center.x - innerStart.x), 2)) + (Math.pow((center.y - innerStart.y), 2)));
const centerDistance: number = Math.sqrt((Math.pow((center.x - pointPosition.x), 2)) + (Math.pow((center.y - pointPosition.y), 2)));
if (range.roundedCornerRadius <= 0) {
widthDifference = widthDifference === 0 ? 1 : widthDifference;
innerEnd.y = (range.position === 'Cross' && axis.direction === 'ClockWise') ? degree > 325 ?
innerEnd.y - (widthDifference / 2) : innerEnd.y : innerEnd.y;
const degreeValue: number = range.position === 'Cross' ? 330 : 325;
if (((degreeValue <= degree && degree <= 360))) {
arcStartTwo = (axis.direction === 'ClockWise' ? (centerDistance / 2)
: (degree >= 345 ? (startRadius - (widthDifference / 2) - (endWidth / 2))
: range.position === 'Cross' ? (startRadius + (widthDifference / 4) - (startWidth / 2))
: (startRadius - (widthDifference / 2) - (startWidth / 2))));
arcEndTwo = (axis.direction === 'ClockWise' ? (centerStartDistance / 2)
: range.position === 'Cross' ?
(endRadius + (widthDifference / 4)) - (endWidth / 4) :
(range.position === 'Outside' && axis.direction === 'AntiClockWise') ? degree < 345 ?
(startRadius - (widthDifference) - (endWidth / 4))
: (startRadius - (widthDifference / 2))
: (endRadius + (widthDifference / 2)) - (endWidth / 2));
return arcPath(start, end, radius, endRadii, endRadii, arcStartTwo, arcEndTwo, clockWise,
innerStart, innerEnd, pointPosition);
} else if ((degree > 260 && degree < 325) && range.position !== 'Cross' && range.position !== 'Outside') {
let arcStart: number = (arcRadius - (widthDifference / 2));
const arcEnd: number = (arcRadius - (widthDifference / 2));
const angleValueDirection: boolean = axis.direction === 'ClockWise' ? degree >= 310 : degree < 345;
if (degree < 310) {
return arcWidthPath(start, end, innerStart, innerEnd, radius, arcStart, arcEnd, clockWise);
} else if (degree >= 310 || angleValueDirection) {
arcStart = (arcRadius - (widthDifference));
return arcWidthPath(start, end, innerStart, innerEnd, radius, arcEnd, arcStart, clockWise);
} else {
return arcWidthPath(start, end, innerStart, innerEnd, radius, startRadius, endRadius, clockWise);
}
} else {
if (range.position === 'Cross') {
const endRadiusValue: number = axis.direction === 'ClockWise' ? degree <= 300 && degree >= 260 ?
endRadius - (widthDifference / 2) - (startWidth / 4) : endRadius
- (widthDifference) - (startWidth / 2) : degree <= 300 && degree >= 260 ?
endRadius + (widthDifference / 4) - (startWidth / 4) :
endRadius + (widthDifference / 4) - (startWidth / 2);
const startRadiusValue: number = axis.direction === 'ClockWise' ? degree > 325 ? degree > 340 ? (startRadius - startWidth)
- (widthDifference / 4) : startRadius - (widthDifference / 4)
: startRadius : startRadius - (widthDifference / 4);
return arcWidthPath(start, end, innerStart, innerEnd, radius, startRadiusValue, endRadiusValue, clockWise);
} else if (range.position === 'Outside') {
if (degree < 325 && degree > 285) {
let arcTwo: number;
const startGreater: number = startWidth / 2;
const endGreater: number = endWidth / 2;
const arcOne: number = arcTwo = arcRadius + (widthDifference / 2) + startGreater + endGreater;
innerEnd.y = axis.direction === 'ClockWise' && startWidth !== endWidth && startWidth > widthDifference ?
innerEnd.y - (widthDifference / 2) : innerEnd.y + startGreater;
return arcWidthPath(start, end, innerStart, innerEnd, radius, arcOne, arcTwo, clockWise);
} else {
return arcWidthPath(start, end, innerStart, innerEnd, radius, arcRadius, arcRadius, clockWise);
}
} else {
return arcWidthPath(start, end, innerStart, innerEnd, radius, startRadius, endRadius, clockWise);
}
}
} else {
const degreeAngle: number = axis.endAngle < 4 ? 356 : 360;
clockWise = degree > degreeAngle ? 0 : clockWise;
const degreeValueOne: number = axis.direction === 'ClockWise' ? 327 : 322;
const degreeValueTwo: number = axis.direction === 'ClockWise' ? 328 : 325;
if ((endWidth === startWidth) && (axis.startAngle !== 0 || axis.endAngle !== 0)) {
return roundedArcWidthPathCalculation(start, end, innerStart, innerEnd, radius, startRadius, endRadius,
clockWise, outerOldEnd, innerOldEnd, outerOldStart, innerOldStart);
} else if ((degree <= degreeAngle && degree > degreeValueOne) && range.roundedCornerRadius > 0) {
arcStartOne = axis.direction === 'ClockWise' ? degree < 334 && degree > 324 ? endRadii - (widthDifference / 2) :
endRadii - (widthDifference / 4) : endRadii;
arcStartTwo = (centerDistance / 2);
arcEndTwo = axis.direction === 'ClockWise' ? ((centerStartDistance / 2) + (widthDifference / 2)) :
(centerStartDistance / 2);
return arcRoundedPath(start, end, radius, outerOldEnd, innerOldEnd, arcStartOne, endRadii,
arcStartTwo, arcEndTwo, clockWise, innerStart, innerEnd,
innerOldStart, outerOldStart, pointPosition);
} else if (degree > 270 && degree < degreeValueTwo) {
const startAddArc: number = endRadius + (widthDifference / 2) - (endWidth / 2);
const startSubArc: number = endRadius - (widthDifference / 2) - (endWidth / 2);
arcStartOne = (startRadius - (widthDifference / 2) - (startWidth / 2));
arcEndOne = (axis.direction === 'ClockWise' ? startSubArc : startAddArc);
return arcRoundedPath(start, end, radius, outerOldEnd, innerOldEnd, arcStartOne, arcEndOne,
null, null, clockWise, innerStart, innerEnd, innerOldStart, outerOldStart, null);
} else {
return roundedArcWidthPathCalculation(start, end, innerStart, innerEnd,
radius, startRadius, endRadius, clockWise,
outerOldEnd, innerOldEnd, outerOldStart, innerOldStart);
}
}
} else {
return roundedArcWidthPathCalculation(start, end, innerStart, innerEnd,
radius, startRadius, endRadius, clockWise,
outerOldEnd, innerOldEnd, outerOldStart, innerOldStart);
}
}
/**
* Function to get start and end width range rounded path calculation to the circular gauge.
*
* @param {GaugeLocation} start - Specifies the start value.
* @param {GaugeLocation} end - Specifies the end value.
* @param {GaugeLocation} innerStart - Specifies the innerStart value.
* @param {GaugeLocation} innerEnd - Specifies the innerEnd value.
* @param {number} radius - Specifies the radius value.
* @param {number} startRadius - Specifies the startRadius value.
* @param {number} endRadius - Specifies the endRadius value.
* @param {number} clockWise - Specifies the clockWise value.
* @param {GaugeLocation} outerOldEnd - Specifies the outerOldEnd value.
* @param {GaugeLocation} innerOldEnd - Specifies the innerOldEnd value.
* @param {GaugeLocation} outerOldStart - Specifies the outerOldStart value.
* @param {GaugeLocation} innerOldStart - Specifies the innerOldStart value.
* @returns {string} - Returns the path value.
* @private
*/
export function roundedArcWidthPathCalculation(
start: GaugeLocation, end: GaugeLocation, innerStart: GaugeLocation, innerEnd: GaugeLocation,
radius: number, startRadius: number, endRadius: number, clockWise: number,
outerOldEnd: GaugeLocation, innerOldEnd: GaugeLocation, outerOldStart: GaugeLocation,
innerOldStart: GaugeLocation
): string {
return 'M ' + start.x + ' ' + start.y + ' A ' + radius + ' ' + radius + ' 0 ' +
clockWise + ' 1 ' + end.x + ' ' + end.y + ' C ' + outerOldEnd.x + ' ' + outerOldEnd.y + ' ' + innerOldEnd.x + ' ' +
innerOldEnd.y + ' ' + innerEnd.x + ' ' + innerEnd.y +
' A ' + endRadius + ' ' + startRadius + ' 0 ' +
clockWise + ' 0 ' + innerStart.x + ' ' + innerStart.y +
' C ' + innerOldStart.x + ' ' + innerOldStart.y + ' ' + outerOldStart.x + ' ' +
outerOldStart.y + ' ' + start.x + ' ' + start.y + ' Z';
}
/**
* Function to get the rounded path direction of the circular gauge.
*
* @param {GaugeLocation} center - Specifies the center value.
* @param {number} actualStart - Specifies the actualStart value.
* @param {number} actualEnd - Specifies the actualEnd value.
* @param {number} oldStart - Specifies the oldStart value.
* @param {number} oldEnd - Specifies the oldEnd value.
* @param {number} radius - Specifies the radius value.
* @param {number} startWidth - Specifies the startWidth value.
* @param {number} endWidth - Specifies the endWidth value.
* @param {Range} range - Specifies the range value.
* @param {Axis} axis - Specifies the axis value.
* @returns {string} - Returns the path value.
* @private
*/
export function getRoundedPathArc(
center: GaugeLocation, actualStart: number, actualEnd: number, oldStart: number, oldEnd: number,
radius: number, startWidth?: number, endWidth?: number, range?: Range, axis?: Axis
): string {
actualEnd -= isCompleteAngle(actualStart, actualEnd) ? 0.0001 : 0;
const degree: number = getDegree(actualStart, actualEnd);
const startRadius: number = radius - startWidth;
const endRadius: number = radius - endWidth;
const arcRadius: number = radius - ((startWidth + endWidth) / 2);
return arcWidthPathCalculation(
getLocationFromAngle(actualStart, radius, center),
getLocationFromAngle(actualEnd, radius, center),
getLocationFromAngle(actualStart, startRadius, center),
getLocationFromAngle(actualEnd, endRadius, center),
radius, arcRadius, arcRadius, arcRadius,
(degree < 180) ? 0 : 1, center,
getLocationFromAngle(oldEnd, radius, center),
getLocationFromAngle(oldEnd, endRadius, center),
getLocationFromAngle(oldStart, radius, center),
getLocationFromAngle(oldStart, startRadius, center),
startWidth, endWidth, degree, range, axis
);
}
/**
* Function to get the circular path direction of the circular gauge.
*
* @param {GaugeLocation} start - Specifies the start value.
* @param {GaugeLocation} end - Specifies the end value.
* @param {number} radius - Specifies the radius value.
* @param {number} clockWise - Specifies the clockWise.
* @returns {string} - Returns the path.
* @private
*/
export function getCirclePath(start: GaugeLocation, end: GaugeLocation, radius: number, clockWise: number): string {
return 'M ' + start.x + ' ' + start.y + ' A ' + radius + ' ' +
radius + ' 0 ' + clockWise + ' 1 ' + end.x + ' ' + end.y;
}
/**
* Function to compile the template function for circular gauge.
*
* @param {string} template - Specifies the template.
* @param {CircularGauge} gauge - Specifies the gauge instance.
* @returns {Function} - Returns the template function.
* @private
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getTemplateFunction(template: string | Function, gauge: CircularGauge): any {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let templateFn: any = null;
try {
if (typeof template === 'function') {
templateFn = templateComplier(template);
} else if (isNaN(parseFloat(template)) && document.querySelectorAll(template).length) {
if ((template.charAt(0) !== 'a' || template.charAt(0) !== 'A') && template.length !== 1) {
templateFn = templateComplier(document.querySelector(template).innerHTML.trim());
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} else if ((gauge as any).isVue || (gauge as any).isVue3) {
templateFn = templateComplier(template);
}
} catch (e) {
templateFn = templateComplier(template);
}
return templateFn;
}
/**
* Function to remove the element from id.
*
* @param {string} id Specifies the id
* @returns {void}
* @private
*/
export function removeElement(id: string): void {
const element: Element = getElement(id);
if (element) {
remove(element);
}
}
/**
* Function to get element from id.
*
* @param {string} id - Specifies the id.
* @returns {Element} - Returns the element.
* @private
*/
export function getElement(id: string): Element {
return document.getElementById(id);
}
/**
* Function to convert the number from string.
*
* @param {string} value - Specifies the value.
* @param {number} containerSize - Specifies the container size.
* @returns {number} - Returns the number.
* @private
*/
export function stringToNumber(value: string, containerSize: number): number {
if (value !== null && value !== undefined) {
return value.indexOf('%') !== -1 ? (containerSize / 100) * parseInt(value, 10) : parseInt(value, 10);
}
return null;
}
/**
* Function to get current point for circular gauge using element id.
*
* @param {string} targetId - Specifies the target id.
* @param {CircularGauge} gauge - Specifies the gauge instance.
* @returns {IVisiblePointer} - Returns the pointer and axis index.
* @private
*/
export function getPointer(targetId: string, gauge: CircularGauge): IVisiblePointer {
const tempString: string = targetId.replace(gauge.element.id, '').split('_Axis_')[1];
const tempStringArray: string[] = tempString.indexOf('_Range_') > -1 ? tempString.split('_Range_') : tempString.indexOf('_Pointer_NeedleCap_') > -1 ? tempString.split('_Pointer_NeedleCap_') :
tempString.indexOf('_Pointer_NeedleTail_') > -1 ? tempString.split('_Pointer_NeedleTail_') : tempString.indexOf('_Pointer_NeedleRect_') > -1 ? tempString.split('_Pointer_NeedleRect_') :
tempString.indexOf('_Pointer_Needle_') > -1 ? tempString.split('_Pointer_Needle_') : tempString.indexOf('_Pointer_RangeBar_') > -1 ? tempString.split('_Pointer_RangeBar_') : tempString.indexOf('_Pointer_Marker_') > -1 ?
tempString.split('_Pointer_Marker_') : tempString.indexOf('_Pointer_') > -1 ? tempString.split('_Pointer_') : tempString.split('_Annotation_') ;
return {
axisIndex: +tempStringArray[0],
pointerIndex: +tempStringArray[tempStringArray.length - 1]
};
}
/**
* Function to convert the label using format for cirular gauge.
*
* @param {string} format - Specifies the format.
* @returns {string} - Returns th string.
* @private
*/
export function getLabelFormat(format: string): string {
const customLabelFormat: boolean = format && format.match('{value}') !== null;
const skeleton: string = customLabelFormat ? '' : format;
return skeleton;
}
/**
* Function to calculate the marker shape for circular gauge.
*
* @param {GaugeLocation} location - Specifies the location.
* @param {string} shape - Specifies the shape.
* @param {Size} size - Specifies the size.
* @param {string} url - Specifies the url.
* @param {PathOption} options - Specifies the path option.
* @returns {PathOption} - Returns the path.
* @private
*/
export function calculateShapes(location: GaugeLocation, shape: string, size: Size, url: string, options: PathOption): PathOption {
let path: string;
const width: number = typeof size.width === 'string' ? parseFloat(<string>size.width) : size.width;
const height: number = typeof size.height === 'string' ? parseFloat(<string>size.height) : size.height;
const locX: number = location.x;
const locY: number = location.y;
const x: number = location.x + (-width / 2);
const y: number = location.y + (-height / 2);
const isLegend: boolean = options.id.indexOf('Shape') > -1;
let space: number;
switch (shape) {
case 'Circle':
merge(options, { 'rx': width / 2, 'ry': height / 2, 'cx': locX, 'cy': locY });
break;
case 'Diamond':
path = 'M' + ' ' + x + ' ' + locY + ' ' +
'L' + ' ' + locX + ' ' + (locY + (-height / 2)) + ' ' +
'L' + ' ' + (locX + (width / 2)) + ' ' + locY + ' ' +
'L' + ' ' + locX + ' ' + (locY + (height / 2)) + ' ' +
'L' + ' ' + x + ' ' + locY + ' Z';
merge(options, { 'd': path });
break;
case 'Rectangle':
path = 'M' + ' ' + x + ' ' + (locY + (-height / 2)) + ' ' +
'L' + ' ' + (locX + (width / 2)) + ' ' + (locY + (-height / 2)) + ' ' +
'L' + ' ' + (locX + (width / 2)) + ' ' + (locY + (height / 2)) + ' ' +
'L' + ' ' + x + ' ' + (locY + (height / 2)) + ' ' +
'L' + ' ' + x + ' ' + (locY + (-height / 2)) + ' Z';
merge(options, { 'd': path });
break;
case 'Triangle':
if (isLegend) {
path = 'M' + ' ' + (x + (width / 2)) + ' ' + y + ' ' + 'L' + ' ' + (x + width) + ' ' +
(y + height) + 'L' + ' ' + x + ' ' + (y + height) + ' Z';
} else {
path = 'M' + ' ' + locX + ' ' + locY + ' ' +
'L' + ' ' + (locX - height) + ' ' + (locY - (width / 2)) +
'L' + ' ' + (locX - height) + ' ' + (locY + (width / 2)) + ' Z';
}
merge(options, { 'd': path });
break;
case 'InvertedTriangle':
if (isLegend) {
path = 'M' + ' ' + (x + width) + ' ' + y + ' ' + 'L' + ' ' + (x + (width / 2)) + ' ' + (y + height) +
'L' + ' ' + x + ' ' + (y) + ' Z';
} else {
path = 'M' + ' ' + locX + ' ' + locY + ' ' +
'L' + ' ' + (locX + height) + ' ' + (locY - (width / 2)) +
'L' + ' ' + (locX + height) + ' ' + (locY + (width / 2)) + ' Z';
}
merge(options, { 'd': path });
break;
case 'Image':
merge(options, { 'href': url, 'height': height, 'width': width, x: x, y: y });
break;
case 'RightArrow':
space = 2;
path = 'M' + ' ' + (locX + (-width / 2)) + ' ' + (locY - (height / 2)) + ' ' +
'L' + ' ' + (locX + (width / 2)) + ' ' + (locY) + ' ' + 'L' + ' ' +
(locX + (-width / 2)) + ' ' + (locY + (height / 2)) + ' L' + ' ' + (locX + (-width / 2)) + ' ' +
(locY + (height / 2) - space) + ' ' + 'L' + ' ' + (locX + (width / 2) - (2 * space)) + ' ' + (locY) +
' L' + (locX + (-width / 2)) + ' ' + (locY - (height / 2) + space) + ' Z';
merge(options, { 'd': path });
break;
case 'LeftArrow':
options.fill = options.stroke;
options.stroke = 'transparent';
space = 2;
path = 'M' + ' ' + (locX + (width / 2)) + ' ' + (locY - (height / 2)) + ' ' +
'L' + ' ' + (locX + (-width / 2)) + ' ' + (locY) + ' ' + 'L' + ' ' +
(locX + (width / 2)) + ' ' + (locY + (height / 2)) + ' ' + 'L' + ' ' +
(locX + (width / 2)) + ' ' + (locY + (height / 2) - space) + ' L' + ' ' + (locX + (-width / 2) + (2 * space))
+ ' ' + (locY) + ' L' + (locX + (width / 2)) + ' ' + (locY - (height / 2) + space) + ' Z';
merge(options, { 'd': path });
break;
}
return options;
}
/** @private */
export class CustomizeOption {
public id: string;
constructor(id?: string) {
this.id = id;
}
}
/** @private */
export class PathOption extends CustomizeOption {
public opacity: number;
public fill: string;
public stroke: string;
public ['stroke-width']: number;
public ['stroke-dasharray']: string;
public d: string;
public transform: string;
public style: string;
constructor(
id: string, fill: string, width: number, color: string,
opacity?: number, dashArray?: string, d?: string, transform: string = '', style: string = ''
) {
super(id);
this.opacity = opacity;
this.fill = fill;
this.stroke = color;
this['stroke-width'] = width;
this['stroke-dasharray'] = dashArray;
this.d = d;
this.transform = transform;
this.style = style;
}
}
/** @private */
export class RectOption extends CustomizeOption {
public x: number;
public y: number;
public height: number;
public width: number;
public opacity: number;
public fill: string;
public stroke: string;
public ['stroke-width']: number;
public ['stroke-dasharray']: string;
constructor(
id: string, fill: string, border: BorderModel, opacity: number, rect: Rect
) {
super(id);
this.y = rect.y;
this.x = rect.x;
this.height = rect.height;
this.width = rect.width;
this.opacity = opacity;
this.fill = fill;
this.stroke = border.color;
this['stroke-width'] = border.width;
this['stroke-dasharray'] = border.dashArray;
}
}
/**
* Specifies the size information of an element.
*/
export class Size {
/**
* Specifies the height of an element.
*/
public height: number;
/**
* Specifies the width of an element.
*/
public width: number;
constructor(width: number, height: number) {
this.width = width;
this.height = height;
}
}
/**
* Specifies the location of the element in the circular gauge.
*/
export class GaugeLocation {
/**
* Specifies the x position of the location in pixels.
*/
public x: number;
/**
* Specifies the y position of the location in pixels.
*/
public y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
/** @private */
export class Rect {
public x: number;
public y: number;
public height: number;
public width: number;
constructor(x: number, y: number, width: number, height: number) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
}
/** @private */
export class TextOption extends CustomizeOption {
public anchor: string;
public text: string;
public transform: string = '';
public x: number;
public y: number;
public baseLine: string = 'auto';
constructor(id?: string, x?: number, y?: number, anchor?: string, text?: string, transform: string = '', baseLine?: string) {
super(id);
this.x = x;
this.y = y;
this.anchor = anchor;
this.text = text;
this.transform = transform;
this.baseLine = baseLine;
}
}
/** @private */
export class VisibleLabels {
public text: string;
public value: number;
public size: Size;
constructor(text: string, value: number, size?: Size) {
this.text = text;
this.value = value;
this.size = size;
}
}