UNPKG

@syncfusion/ej2-progressbar

Version:
342 lines (341 loc) 21.1 kB
import { ProgressAnimation } from '../utils/progress-animation'; import { PathOption, getElement, measureText } from '@syncfusion/ej2-svg-base'; import { stringToNumber, getPathArc, degreeToLocation } from '../utils/helper'; import { Segment } from './segment-progress'; import { TextOption } from '../utils/helper'; import { animationMode } from '@syncfusion/ej2-base'; /** * Progressbar of type circular */ var Circular = /** @class */ (function () { function Circular(progress) { this.segment = new Segment(); this.animation = new ProgressAnimation(); this.progress = progress; } /** * To render the circular track. * * @returns {void} */ Circular.prototype.renderCircularTrack = function () { var progress = this.progress; var circularTrackGroup = progress.renderer.createGroup({ 'id': progress.element.id + '_CircularTrackGroup' }); var radius; var endAngle; var startAngle = progress.startAngle; progress.totalAngle = (progress.endAngle - progress.startAngle) % 360; progress.totalAngle = (progress.totalAngle <= 0 ? (360 + progress.totalAngle) : progress.totalAngle); progress.totalAngle -= (progress.totalAngle === 360) ? 0.01 : 0; this.trackEndAngle = endAngle = (progress.startAngle + ((progress.enableRtl) ? -progress.totalAngle : +progress.totalAngle)) % 360; this.centerX = progress.progressRect.x + (progress.progressRect.width / 2); this.centerY = progress.progressRect.y + (progress.progressRect.height / 2); this.maxThickness = Math.max(progress.trackThickness, progress.progressThickness) || Math.max(progress.themeStyle.circularProgressThickness, progress.themeStyle.circularTrackThickness); this.availableSize = (Math.min(progress.progressRect.height, progress.progressRect.width) / 2) - this.maxThickness / 2; radius = stringToNumber(progress.radius, this.availableSize); radius = (radius === null) ? 0 : radius; var stroke = (progress.argsData.trackColor || progress.themeStyle.circularTrackColor); var fill = (progress.enablePieProgress) ? (progress.argsData.trackColor || progress.themeStyle.circularTrackColor) : 'none'; var strokeWidth = (progress.enablePieProgress) ? 0 : (progress.trackThickness || progress.themeStyle.circularTrackThickness); var circularPath = getPathArc(this.centerX, this.centerY, radius, startAngle, endAngle, progress.enableRtl, progress.enablePieProgress); this.isRange = (this.progress.rangeColors[0].color !== '' || this.progress.rangeColors[0].start !== null || this.progress.rangeColors[0].end !== null); var option = new PathOption(progress.element.id + '_Circulartrack', fill, strokeWidth, stroke, progress.themeStyle.trackOpacity, '0', circularPath); var circularTrack = progress.renderer.drawPath(option); progress.trackWidth = circularTrack.getTotalLength(); if (progress.segmentCount > 1 && !progress.enableProgressSegments && !progress.enablePieProgress && !this.isRange) { progress.segmentSize = progress.calculateSegmentSize(progress.trackWidth, strokeWidth); circularTrack.setAttribute('stroke-dasharray', progress.segmentSize); } if (progress.cornerRadius === 'Round' && !progress.enablePieProgress && !this.isRange) { circularTrack.setAttribute('stroke-linecap', 'round'); } circularTrackGroup.appendChild(circularTrack); progress.svgObject.appendChild(circularTrackGroup); }; /** * Renders circular progress to update previous progress. * * @param {number} previousEnd - The previous end value of the progress. * @param {number} previousTotalEnd - The previous total end value of the progress. * @param {boolean} refresh - Indicates whether to refresh the progress. * @returns {void} */ Circular.prototype.renderCircularProgress = function (previousEnd, previousTotalEnd, refresh) { var progress = this.progress; var startAngle = progress.startAngle; var endAngle; var totalAngle; var radius; var previousPath; var progressTotalAngle; var progressEnd; var circularProgress; var linearClipPath; var circularProgressGroup; var segmentWidth; if (!refresh) { circularProgressGroup = progress.renderer.createGroup({ 'id': progress.element.id + '_CircularProgressGroup' }); } else { circularProgressGroup = getElement(progress.element.id + '_CircularProgressGroup'); } radius = stringToNumber(progress.innerRadius, this.availableSize); radius = (radius === null) ? 0 : radius; progress.previousTotalEnd = progressEnd = progress.calculateProgressRange(progress.argsData.value > progress.maximum ? progress.maximum : progress.argsData.value); var progressEndAngle = (progress.startAngle + ((progress.enableRtl) ? -progressEnd : progressEnd)) % 360; progress.previousEndAngle = endAngle = ((progress.isIndeterminate && !progress.enableProgressSegments) ? (progress.startAngle + ((progress.enableRtl) ? -progress.totalAngle : progress.totalAngle)) % 360 : progressEndAngle); progressTotalAngle = (progressEnd - progress.startAngle) % 360; progressTotalAngle = (progressTotalAngle <= 0 ? (360 + progressTotalAngle) : progressTotalAngle); progressTotalAngle -= (progressTotalAngle === 360) ? 0.01 : 0; var circularPath = getPathArc(this.centerX, this.centerY, radius, startAngle, endAngle, progress.enableRtl, progress.enablePieProgress); var stroke = this.checkingCircularProgressColor(); var fill = (progress.enablePieProgress) ? stroke : 'none'; var thickness = (progress.progressThickness || progress.themeStyle.circularProgressThickness); var strokeWidth = (progress.enablePieProgress) ? 0 : thickness; var option = new PathOption(progress.element.id + '_Circularprogress', fill, strokeWidth, stroke, progress.themeStyle.progressOpacity, '0', circularPath); progress.progressWidth = progress.renderer.drawPath(option).getTotalLength(); progress.segmentSize = this.validateSegmentSize(progress, thickness); this.endPosition = degreeToLocation(this.centerX, this.centerY, radius, endAngle); if (progress.secondaryProgress !== null && !progress.isIndeterminate) { this.renderCircularBuffer(progress, radius, progressTotalAngle); } if (progress.argsData.value !== null) { if (progress.segmentColor.length !== 0 && !progress.isIndeterminate && !progress.enablePieProgress) { totalAngle = (!progress.enableProgressSegments) ? progress.totalAngle : progressTotalAngle; segmentWidth = (!progress.enableProgressSegments) ? progress.trackWidth : progress.progressWidth; circularProgress = this.segment.createCircularSegment(progress, '_CircularProgressSegment', this.centerX, this.centerY, radius, progress.argsData.value, progress.themeStyle.progressOpacity, thickness, totalAngle, segmentWidth); } else if (this.isRange && !progress.isIndeterminate) { circularProgress = this.segment.createCircularRange(this.centerX, this.centerY, radius, progress); } else { if (!refresh) { circularProgress = progress.renderer.drawPath(option); } else { circularProgress = getElement(progress.element.id + '_Circularprogress'); previousPath = circularProgress.getAttribute('d'); circularProgress.setAttribute('stroke', stroke); circularProgress.setAttribute('d', circularPath); } if (progress.segmentCount > 1 && !progress.enablePieProgress) { circularProgress.setAttribute('stroke-dasharray', progress.segmentSize); } if (progress.cornerRadius === 'Round' && startAngle !== endAngle) { circularProgress.setAttribute('stroke-linecap', 'round'); } } circularProgressGroup.appendChild(circularProgress); if (progress.isActive && !progress.isIndeterminate && !progress.enablePieProgress) { this.renderActiveState(circularProgressGroup, radius, strokeWidth, circularPath, progressEndAngle, progressEnd, refresh); } if (((progress.animation.enable && animationMode !== 'Disable') || animationMode === 'Enable') || progress.isIndeterminate) { this.delay = (progress.secondaryProgress !== null) ? 300 : progress.animation.delay; linearClipPath = progress.createClipPath(progress.clipPath, null, refresh ? previousPath : '', refresh); circularProgressGroup.appendChild(progress.clipPath); if (((progress.animation.enable && animationMode !== 'Disable') || animationMode === 'Enable') && !progress.isIndeterminate && !progress.isActive) { circularProgress.style.clipPath = 'url(#' + progress.element.id + '_clippath)'; this.animation.doCircularAnimation(this.centerX, this.centerY, radius, progressEndAngle, progressEnd, linearClipPath, progress, thickness, this.delay, refresh ? previousEnd : null, refresh ? previousTotalEnd : null); } if (progress.isIndeterminate) { if (progress.enableProgressSegments) { linearClipPath.setAttribute('d', getPathArc(this.centerX, this.centerY, radius + (thickness / 2), progress.startAngle, this.trackEndAngle, progress.enableRtl, true)); } circularProgress.setAttribute('style', 'clip-path:url(#' + progress.element.id + '_clippath)'); this.animation.doCircularIndeterminate((!progress.enableProgressSegments) ? linearClipPath : circularProgress, progress, startAngle, progressEndAngle, this.centerX, this.centerY, radius, thickness, linearClipPath); } } progress.svgObject.appendChild(circularProgressGroup); } }; /** * Renders circular buffer for the progress bar. * * @param {ProgressBar} progress - The progress bar control. * @param {number} radius - The radius of the circular buffer. * @param {number} progressTotalAngle - The total angle covered by the progress. * @returns {void} * @private */ Circular.prototype.renderCircularBuffer = function (progress, radius, progressTotalAngle) { var bufferClipPath; var circularBuffer; var segmentWidth; var totalAngle; var circularBufferGroup = progress.renderer.createGroup({ 'id': progress.element.id + '_ CircularBufferGroup' }); var bufferEnd = progress.calculateProgressRange(progress.secondaryProgress > progress.maximum ? progress.maximum : progress.secondaryProgress); var endAngle = (progress.startAngle + ((progress.enableRtl) ? -bufferEnd : bufferEnd)) % 360; var circularPath = getPathArc(this.centerX, this.centerY, radius, progress.startAngle, endAngle, progress.enableRtl, progress.enablePieProgress); this.bufferEndPosition = degreeToLocation(this.centerX, this.centerY, radius, endAngle); var stroke = progress.secondaryProgressColor ? progress.secondaryProgressColor : progress.themeStyle.bufferColor || this.checkingCircularProgressColor(); var fill = (progress.enablePieProgress) ? stroke : 'none'; var strokeWidth = (progress.enablePieProgress) ? 0 : (progress.secondaryProgressThickness ? progress.secondaryProgressThickness : (progress.progressThickness || progress.themeStyle.circularProgressThickness)); var option = new PathOption(progress.element.id + '_Circularbuffer', fill, strokeWidth, stroke, progress.themeStyle.bufferOpacity, '0', circularPath); if (progress.segmentColor.length !== 0 && !progress.isIndeterminate && !progress.enablePieProgress && !this.isRange) { totalAngle = (!progress.enableProgressSegments) ? progress.totalAngle : progressTotalAngle; segmentWidth = (!progress.enableProgressSegments) ? progress.trackWidth : progress.progressWidth; circularBuffer = this.segment.createCircularSegment(progress, '_CircularBufferSegment', this.centerX, this.centerY, radius, progress.secondaryProgress > progress.maximum ? progress.maximum : progress.secondaryProgress, progress.themeStyle.bufferOpacity, strokeWidth, totalAngle, segmentWidth); } else { circularBuffer = progress.renderer.drawPath(option); if (progress.segmentCount > 1 && !progress.enablePieProgress && !this.isRange) { circularBuffer.setAttribute('stroke-dasharray', progress.segmentSize); } if (progress.cornerRadius === 'Round' && !this.isRange) { circularBuffer.setAttribute('stroke-linecap', 'round'); } } circularBufferGroup.appendChild(circularBuffer); if (((progress.animation.enable && animationMode !== 'Disable') || animationMode === 'Enable') && !progress.isActive) { bufferClipPath = progress.createClipPath(progress.bufferClipPath, null, '', false); circularBufferGroup.appendChild(progress.bufferClipPath); circularBuffer.setAttribute('style', 'clip-path:url(#' + progress.element.id + '_clippathBuffer)'); this.animation.doCircularAnimation(this.centerX, this.centerY, radius, endAngle, bufferEnd, bufferClipPath, progress, (progress.progressThickness || progress.themeStyle.circularProgressThickness), progress.animation.delay); } progress.svgObject.appendChild(circularBufferGroup); }; /** * To render the circular Label. * * @param {boolean} isProgressRefresh - Indicates whether progress should be refreshed. Defaults to false. * @returns {void} */ Circular.prototype.renderCircularLabel = function (isProgressRefresh) { if (isProgressRefresh === void 0) { isProgressRefresh = false; } var end; var circularLabel; var centerY; var textSize; var option; var percentage = 100; var progress = this.progress; var labelText = progress.labelStyle.text; var circularLabelGroup = progress.renderer.createGroup({ 'id': progress.element.id + '_CircularLabelGroup' }); if (document.getElementById(circularLabelGroup.id)) { document.getElementById(circularLabelGroup.id).remove(); } var labelValue = ((progress.value - progress.minimum) / (progress.maximum - progress.minimum)) * percentage; var circularValue = (progress.value < progress.minimum) ? 0 : +labelValue.toFixed(2); var argsData = { cancel: false, text: labelText ? labelText : String(circularValue) + '%', color: progress.labelStyle.color || progress.themeStyle.circularLabelFont.color }; progress.trigger('textRender', argsData); if (!argsData.cancel) { textSize = measureText(argsData.text, progress.labelStyle, progress.themeStyle.circularLabelFont); centerY = this.centerY + (textSize.height / 2); option = new TextOption(progress.element.id + '_circularLabel', progress.labelStyle.size || progress.themeStyle.circularLabelFont.size, progress.labelStyle.fontStyle || progress.themeStyle.circularLabelFont.fontStyle, progress.labelStyle.fontFamily || progress.themeStyle.circularLabelFont.fontFamily, progress.labelStyle.fontWeight || progress.themeStyle.circularLabelFont.fontWeight, 'middle', argsData.color, this.centerX, centerY, progress.progressRect.width, progress.progressRect.height); circularLabel = progress.renderer.createText(option, argsData.text); circularLabelGroup.appendChild(circularLabel); if (((progress.animation.enable && animationMode !== 'Disable') || animationMode === 'Enable') && !progress.isIndeterminate) { end = ((progress.value - progress.minimum) / (progress.maximum - progress.minimum)) * progress.totalAngle; end = (progress.value < progress.minimum) ? 0 : end; this.animation.doLabelAnimation(circularLabel, isProgressRefresh ? progress.previousWidth : progress.startAngle, end, progress, this.delay); } progress.svgObject.appendChild(circularLabelGroup); progress.previousWidth = end; } }; /** * Renders the active state of the circular progress. * * @param {Element} progressGroup - The group element containing the progress. * @param {number} radius - The radius of the circular progress. * @param {number} strokeWidth - The width of the progress stroke. * @param {string} circularPath - The path representing the circular progress. * @param {number} endAngle - The angle at which the progress ends. * @param {number} totalEnd - The total end value of the progress. * @param {boolean} refresh - Indicates whether the progress should be refreshed. * @returns {void} * @private */ Circular.prototype.renderActiveState = function (progressGroup, radius, strokeWidth, circularPath, endAngle, totalEnd, refresh) { var circularActive; var option; var progress = this.progress; var thickness = strokeWidth + 1; if (!refresh) { option = new PathOption(progress.element.id + '_CircularActiveProgress', 'none', thickness, '#ffffff', 0.5, '0', circularPath); circularActive = progress.renderer.drawPath(option); } else { circularActive = getElement(progress.element.id + '_CircularActiveProgress'); circularActive.setAttribute('d', circularPath); } if (progress.segmentCount > 1) { circularActive.setAttribute('stroke-dasharray', progress.segmentSize); } if (progress.cornerRadius === 'Round') { circularActive.setAttribute('stroke-linecap', 'round'); } var activeClip = progress.createClipPath(progress.clipPath, null, '', refresh); circularActive.setAttribute('style', 'clip-path:url(#' + progress.element.id + '_clippath)'); progressGroup.appendChild(circularActive); progressGroup.appendChild(progress.clipPath); this.animation.doCircularAnimation(this.centerX, this.centerY, radius, endAngle, totalEnd, activeClip, progress, thickness, 0, null, null, circularActive); }; /** * Validates the segment size for the progress bar. * * @param {ProgressBar} progress - The progress bar control. * @param {number} thickness - The thickness of the progress segments. * @returns {string} - The validated segment size. * @private */ Circular.prototype.validateSegmentSize = function (progress, thickness) { var validSegment; var progressSegment; var rDiff = parseInt(progress.radius, 10) - parseInt(progress.innerRadius, 10); if (rDiff !== 0 && !progress.enableProgressSegments) { progressSegment = progress.trackWidth + ((rDiff < 0) ? (progress.trackWidth * Math.abs(rDiff)) / parseInt(progress.radius, 10) : -(progress.trackWidth * Math.abs(rDiff)) / parseInt(progress.radius, 10)); validSegment = progress.calculateSegmentSize(progressSegment, thickness); } else if (progress.enableProgressSegments) { validSegment = progress.calculateSegmentSize(progress.progressWidth, thickness); } else { validSegment = progress.segmentSize; } return validSegment; }; /** * Checks and retrieves the color for the circular progress. * * @returns {string} - The color for the circular progress. * @private */ Circular.prototype.checkingCircularProgressColor = function () { var circularColor; var progress = this.progress; var role = progress.role; switch (role) { case 'Success': circularColor = progress.themeStyle.success; break; case 'Info': circularColor = progress.themeStyle.info; break; case 'Warning': circularColor = progress.themeStyle.warning; break; case 'Danger': circularColor = progress.themeStyle.danger; break; default: circularColor = (progress.argsData.progressColor || progress.themeStyle.circularProgressColor); } return circularColor; }; return Circular; }()); export { Circular };