quasar
Version:
Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time
184 lines (158 loc) • 5.06 kB
JavaScript
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
}
}
})