UNPKG

quasar

Version:

Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time

184 lines (158 loc) 5.06 kB
import { h, computed, getCurrentInstance } from 'vue' import useSize from '../../composables/private.use-size/use-size.js' import { useCircularCommonProps } from './circular-progress.js' import { createComponent } from '../../utils/private.create/create.js' import { hMergeSlotSafely } from '../../utils/private.render/render.js' import { between } from '../../utils/format/format.js' const radius = 50, diameter = 2 * radius, circumference = diameter * Math.PI, strokeDashArray = Math.round(circumference * 1000) / 1000 export default createComponent({ name: 'QCircularProgress', props: { ...useCircularCommonProps, value: { type: Number, default: 0 }, animationSpeed: { type: [String, Number], default: 600 }, indeterminate: Boolean }, setup(props, { slots }) { const { proxy: { $q } } = getCurrentInstance() const sizeStyle = useSize(props) const svgStyle = computed(() => { const angle = ($q.lang.rtl === true ? -1 : 1) * props.angle return { transform: props.reverse !== ($q.lang.rtl === true) ? `scale3d(-1, 1, 1) rotate3d(0, 0, 1, ${-90 - angle}deg)` : `rotate3d(0, 0, 1, ${angle - 90}deg)` } }) const circleStyle = computed(() => props.instantFeedback !== true && props.indeterminate !== true ? { transition: `stroke-dashoffset ${props.animationSpeed}ms ease 0s, stroke ${props.animationSpeed}ms ease` } : '' ) const viewBox = computed(() => diameter / (1 - props.thickness / 2)) const viewBoxAttr = computed( () => `${viewBox.value / 2} ${viewBox.value / 2} ${viewBox.value} ${viewBox.value}` ) const normalized = computed(() => between(props.value, props.min, props.max) ) const range = computed(() => props.max - props.min) const strokeWidth = computed(() => (props.thickness / 2) * viewBox.value) const strokeDashOffset = computed(() => { const dashRatio = (props.max - normalized.value) / range.value const dashGap = props.rounded === true && normalized.value < props.max && dashRatio < 0.25 ? (strokeWidth.value / 2) * (1 - dashRatio / 0.25) : 0 return circumference * dashRatio + dashGap }) function getCircle({ thickness, offset, color, cls, rounded }) { return h('circle', { class: 'q-circular-progress__' + cls + (color !== void 0 ? ` text-${color}` : ''), style: circleStyle.value, fill: 'transparent', stroke: 'currentColor', 'stroke-width': thickness, 'stroke-dasharray': strokeDashArray, 'stroke-dashoffset': offset, 'stroke-linecap': rounded, cx: viewBox.value, cy: viewBox.value, r: radius }) } return () => { const svgChild = [] if (props.centerColor !== void 0 && props.centerColor !== 'transparent') { svgChild.push( h('circle', { class: `q-circular-progress__center text-${props.centerColor}`, fill: 'currentColor', r: radius - strokeWidth.value / 2, cx: viewBox.value, cy: viewBox.value }) ) } if (props.trackColor !== void 0 && props.trackColor !== 'transparent') { svgChild.push( getCircle({ cls: 'track', thickness: strokeWidth.value, offset: 0, color: props.trackColor }) ) } svgChild.push( getCircle({ cls: 'circle', thickness: strokeWidth.value, offset: strokeDashOffset.value, color: props.color, rounded: props.rounded === true ? 'round' : void 0 }) ) const child = [ h( 'svg', { class: 'q-circular-progress__svg', style: svgStyle.value, viewBox: viewBoxAttr.value, 'aria-hidden': 'true' }, svgChild ) ] if (props.showValue === true) { child.push( h( 'div', { class: 'q-circular-progress__text absolute-full row flex-center content-center', style: { fontSize: props.fontSize } }, slots.default !== void 0 ? slots.default() : [h('div', normalized.value)] ) ) } return h( 'div', { class: `q-circular-progress q-circular-progress--${props.indeterminate === true ? 'in' : ''}determinate`, style: sizeStyle.value, role: 'progressbar', 'aria-valuemin': props.min, 'aria-valuemax': props.max, 'aria-valuenow': props.indeterminate === true ? void 0 : normalized.value }, hMergeSlotSafely(slots.internal, child) ) // "internal" is used by QKnob } } })