feat(progress): type prop support dashboard (#2365)

* feat(progress): type props adds dashboard type

* Update src/progress/demos/enUS/index.demo-entry.md

Co-authored-by: gang.yang <gang.yang@tusimple.ai>
Co-authored-by: 07akioni <07akioni2@gmail.com>
This commit is contained in:
gangG 2022-02-11 01:14:45 +08:00 committed by GitHub
parent aefa598bbd
commit a9d6e1d3e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 143 additions and 33 deletions

View File

@ -11,6 +11,7 @@
### Feats
- `n-progress` props `type` add type `dashboard`.
- `n-select` adds `clearFilterAfterSelect` prop, closes [#2352](https://github.com/TuSimple/naive-ui/issues/2352).
### i18n

View File

@ -11,6 +11,7 @@
### Feats
- `n-progress``type` 属性新增 `dashboard` 类型
- `n-select` 新增 `clearFilterAfterSelect` 属性,关闭 [#2352](https://github.com/TuSimple/naive-ui/issues/2352)
### i18n

View File

@ -0,0 +1,17 @@
<markdown>
# Dashboard
Maybe you also need `gapDegree` and `gapPosition` properties to customize the dashboard
</markdown>
<template>
<n-space>
<n-progress type="dashboard" gap-position="bottom" :percentage="50" />
<n-progress
type="dashboard"
gap-position="bottom"
:gap-degree="90"
:percentage="50"
/>
</n-space>
</template>

View File

@ -9,6 +9,7 @@ circle
line
circle-offset.vue
multiple-circle
dashboard.vue
custom-indicator
color
no-indicator
@ -26,6 +27,8 @@ processing
| circle-gap | `number` | `1` | The gap between circles when type is `'multiple-circle'`, suppose `viewbox` size is `100`. | |
| color | `string \| string[]` | `undefined` | Progress color. | |
| fill-border-radius | `number \| string` | `undefined` | `'line'` typed progress's fill's border-radius. Keep `border-radius` if not passed. | |
| gap-degree | `number` | `0` | The gap degree of half circle, 0 ~ 360. | |
| gap-position | `'top' \| 'bottom' \| 'left' \| 'right'` | `'top'` | The gap position. | |
| height | `number` | `undefined` | `'line'` typed progress's height. Keep default height if not passed. | |
| indicator-placement | `'inside' \| 'outside'` | `'outside'` | Indicator placement. | |
| indicator-text-color | `string` | `undefined` | Indicator text color. | |
@ -37,7 +40,7 @@ processing
| show-indicator | `boolean` | `true` | Whether to display indicators. | |
| status | `'default' \| 'success' \| 'error' \| 'warning' \| 'info'` | `'default'` | Progress status. | |
| stroke-width | `number` | `7` | Progress width. | |
| type | `'line' \| 'circle' \| 'multiple-circle'` | `line` | Progress type. | |
| type | `'line' \| 'circle' \| 'multiple-circle' \| 'dashboard'` | `line` | Progress type. | |
| unit | `string` | `%` | Progress unit. | |
### Progress Slots

View File

@ -0,0 +1,17 @@
<markdown>
# 仪表盘
可能你还需要`gapDegree` `gapPosition` 两个属性来自定义仪表盘
</markdown>
<template>
<n-space>
<n-progress type="dashboard" gap-position="bottom" :percentage="50" />
<n-progress
type="dashboard"
gap-position="bottom"
:gap-degree="90"
:percentage="50"
/>
</n-space>
</template>

View File

@ -9,6 +9,7 @@ circle
line
circle-offset.vue
multiple-circle
dashboard.vue
custom-indicator
color
no-indicator
@ -26,6 +27,8 @@ processing
| circle-gap | `number` | `1` | 当类型是 `'multiple-circle'` 的时候圈之间的距离,假设 `viewbox` 的尺寸是 `100` | |
| color | `string \| string[]` | `undefined` | 进度条颜色 | |
| fill-border-radius | `number \| string` | `undefined` | `'line'` 类型进度条填充的圆角半径,不填写则维持 `border-radius` | |
| gap-degree | `number` | `0` | 仪表盘进度条缺口角度,取值范围 0 ~ 360 | |
| gap-position | `'top' \| 'bottom' \| 'left' \| 'right'` | `'top'` | 仪表盘进度条缺口位置 | |
| height | `number` | `undefined` | `'line'` 类型进度条的高度,不填写则维持默认高度 | |
| indicator-placement | `'inside' \| 'outside'` | `'outside'` | 设置指标位置 | |
| indicator-text-color | `string` | `undefined` | 指标文本颜色 | |
@ -37,7 +40,7 @@ processing
| show-indicator | `boolean` | `true` | 是否显示指标 | |
| status | `'default' \| 'success' \| 'error' \| 'warning' \| 'info'` | `'default'` | 进度条状态 | |
| stroke-width | `number` | `7` | 进度条宽度 | |
| type | `'line' \| 'circle' \| 'multiple-circle'` | `line` | 进度条类型 | |
| type | `'line' \| 'circle' \| 'multiple-circle' \| 'dashboard'` | `line` | 进度条类型 | |
| unit | `string` | `%` | 进度条单位 | |
### Progress Slots

View File

@ -1,4 +1,4 @@
import { h, defineComponent, PropType, computed, CSSProperties } from 'vue'
import { h, defineComponent, PropType, CSSProperties } from 'vue'
import { NBaseIcon } from '../../_internal'
import {
SuccessIcon,
@ -43,28 +43,79 @@ export default defineComponent({
},
showIndicator: {
type: Boolean,
reqiuired: true
required: true
},
indicatorTextColor: String,
unit: String,
viewBoxWidth: {
type: Number,
required: true
},
gapDegree: {
type: Number as PropType<number>,
default: 0
},
gapPosition: {
type: String as PropType<'top' | 'bottom' | 'left' | 'right'>,
default: 'bottom'
}
},
setup (props, { slots }) {
const strokeDasharrayRef = computed(() => {
return `${Math.PI * props.percentage}, ${props.viewBoxWidth * 8}`
})
const strokeDashoffsetRef = computed(() => {
return `-${(Math.PI / 3.6) * props.offsetDegree}`
})
function getPathStyles (
percent: number,
offsetDegree: number,
strokeColor?: string
): { pathString: string, pathStyle: CSSProperties } {
const { gapPosition, gapDegree, railStyle, viewBoxWidth } = props
const radius = 50
let beginPositionX = 0
let beginPositionY = -radius
let endPositionX = 0
let endPositionY = -2 * radius
switch (gapPosition) {
case 'left':
beginPositionX = -radius
beginPositionY = 0
endPositionX = 2 * radius
endPositionY = 0
break
case 'right':
beginPositionX = radius
beginPositionY = 0
endPositionX = -2 * radius
endPositionY = 0
break
case 'bottom':
beginPositionY = radius
endPositionY = 2 * radius
break
default:
}
const pathString = `M 55,55 m ${beginPositionX},${beginPositionY}
a ${radius},${radius} 0 1 1 ${endPositionX},${-endPositionY}
a ${radius},${radius} 0 1 1 ${-endPositionX},${endPositionY}`
const len = Math.PI * 2 * radius
const pathStyle = {
stroke: strokeColor,
strokeDasharray: `${(percent / 100) * (len - gapDegree)}px ${
viewBoxWidth * 8
}px`,
strokeDashoffset: `-${
gapDegree / 2 + (Math.PI / 3.6) * offsetDegree
}px`,
railStyle
}
return {
pathString,
pathStyle
}
}
return () => {
const {
fillColor,
railColor,
railStyle,
strokeWidth,
offsetDegree,
status,
percentage,
showIndicator,
@ -72,6 +123,10 @@ export default defineComponent({
unit,
clsPrefix
} = props
const { pathString: railPathString, pathStyle: railPathStyle } =
getPathStyles(100, 0, railColor)
const { pathString: fillPathString, pathStyle: fillPathStyle } =
getPathStyles(percentage, offsetDegree, fillColor)
return (
<div class={`${clsPrefix}-progress-content`} role="none">
<div class={`${clsPrefix}-progress-graph`} aria-hidden>
@ -80,19 +135,11 @@ export default defineComponent({
<g>
<path
class={`${clsPrefix}-progress-graph-circle-rail`}
d="m 55 5 a 50 50 0 1 1 0 100 a 50 50 0 1 1 0 -100"
stroke-width={strokeWidth * 1.1}
d={railPathString}
stroke-width={strokeWidth}
stroke-linecap="round"
fill="none"
style={
[
{
strokeDashoffset: 0,
stroke: railColor
},
railStyle
] as any
}
style={railPathStyle}
/>
</g>
<g>
@ -102,15 +149,11 @@ export default defineComponent({
percentage === 0 &&
`${clsPrefix}-progress-graph-circle-fill--empty`
]}
d="m 55 5 a 50 50 0 1 1 0 100 a 50 50 0 1 1 0 -100"
stroke-width={strokeWidth * 1.1}
d={fillPathString}
stroke-width={strokeWidth}
stroke-linecap="round"
fill="none"
style={{
strokeDasharray: strokeDasharrayRef.value,
strokeDashoffset: strokeDashoffsetRef.value,
stroke: fillColor
}}
style={fillPathStyle}
/>
</g>
</svg>

View File

@ -14,9 +14,16 @@ const progressProps = {
...(useTheme.props as ThemeProps<ProgressTheme>),
processing: Boolean,
type: {
type: String as PropType<'line' | 'circle' | 'multiple-circle'>,
type: String as PropType<
'line' | 'circle' | 'multiple-circle' | 'dashboard'
>,
default: 'line'
},
gapDegree: Number as PropType<number>,
gapPosition: {
type: String as PropType<'top' | 'bottom' | 'left' | 'right'>,
default: 'top'
},
status: {
type: String as PropType<Status>,
default: 'default'
@ -71,6 +78,15 @@ export default defineComponent({
const mergedIndicatorPlacementRef = computed(() => {
return props.indicatorPlacement || props.indicatorPosition
})
const gapDeg = computed(() => {
if (props.gapDegree || props.gapDegree === 0) {
return props.gapDegree
}
if (props.type === 'dashboard') {
return 75
}
return undefined
})
const { mergedClsPrefixRef } = useConfig(props)
const themeRef = useTheme(
'Progress',
@ -83,6 +99,7 @@ export default defineComponent({
return {
mergedClsPrefix: mergedClsPrefixRef,
mergedIndicatorPlacement: mergedIndicatorPlacementRef,
gapDeg,
cssVars: computed(() => {
const { status } = props
const {
@ -144,6 +161,8 @@ export default defineComponent({
processing,
circleGap,
mergedClsPrefix,
gapDeg,
gapPosition,
$slots
} = this
return (
@ -157,9 +176,13 @@ export default defineComponent({
aria-valuemax={100}
aria-valuemin={0}
aria-valuenow={percentage as number}
role={type === 'circle' || type === 'line' ? 'progressbar' : 'none'}
role={
type === 'circle' || type === 'line' || type === 'dashboard'
? 'progressbar'
: 'none'
}
>
{type === 'circle' ? (
{type === 'circle' || type === 'dashboard' ? (
<Circle
clsPrefix={mergedClsPrefix}
status={status}
@ -172,6 +195,8 @@ export default defineComponent({
percentage={percentage as number}
viewBoxWidth={viewBoxWidth}
strokeWidth={strokeWidth}
gapDegree={gapDeg}
gapPosition={gapPosition}
unit={unit}
>
{$slots}

View File

@ -55,7 +55,7 @@ export default c([
`)
])
]),
cM('circle', {
cM('circle, dashboard', {
width: '120px'
}, [
cB('progress-custom-content', `