进度条组件完成重构

master
yutent 2023-11-22 11:34:03 +08:00
parent 3da409d97c
commit 15757f9f7a
1 changed files with 60 additions and 54 deletions

View File

@ -6,7 +6,18 @@
import { css, html, Component, styleMap } from 'wkit'
const RADIUS = 50
const TYPE_LINE = 'line'
const TYPE_CIRCLE = 'circle'
const TYPE_DASHBOARD = 'dashboard'
const RADIUS = 50 // 半径
const PERIMETER = 2 * Math.PI * RADIUS // 周长 2*兀*R
const OFFSET = { circle: 0, dashboard: (-0.25 * PERIMETER) / 2 + 'px' }
const DASH_ARRAY = {
circle: `${PERIMETER}px, ${PERIMETER}px`,
dashboard: `${PERIMETER * 0.75}px, ${PERIMETER}px`
}
class Progress extends Component {
static props = {
@ -17,7 +28,7 @@ class Progress extends Component {
this.value = this.#fix(val)
}
},
type: 'line' // line/circle/dashboard
type: TYPE_LINE
}
static styles = [
@ -31,6 +42,8 @@ class Progress extends Component {
width: 100%;
-webkit-user-select: none;
user-select: none;
--line-width: var(--wc-progress-line-width, 6px);
--base-color: var(--wc-progress-inactive-color, var(--color-plain-2));
&[step='1'] {
--wc-progress-active-color: var(--wc-progress-active-color-1);
@ -90,13 +103,13 @@ class Progress extends Component {
.progress-bar {
display: flex;
width: 100%;
height: var(--wc-progress-line-width, 6px);
height: var(--line-width);
border-radius: 32px;
background: var(--wc-progress-inactive-color, var(--color-plain-2));
background: var(--base-color);
.thumb {
width: 0;
height: var(--wc-progress-line-width, 6px);
height: var(--line-width);
border-radius: 32px;
background: var(--wc-progress-active-color, var(--color-teal-1));
transition: 0.6s ease;
@ -110,45 +123,39 @@ class Progress extends Component {
:host([type='dashboard']) {
width: var(--wc-progress-size, 128px);
height: var(--wc-progress-size, 128px);
svg {
color: var(--wc-progress-active-color);
}
path {
fill: none;
stroke-linecap: round;
stroke-width: var(--line-width);
transition: stroke-dasharray 0.6s ease 0s, stroke 0.6s ease;
}
text {
font-size: calc(var(--line-width) * 4.5);
fill: currentColor;
text-anchor: middle;
alignment-baseline: middle;
}
}
`
]
// 周长
#perimeter = 2 * Math.PI * RADIUS
get trackPath() {
let isDashboard = this.type === 'dashboard'
get #path() {
let n = this.type === TYPE_CIRCLE ? -1 : 1
return `
M 64 64
m 0 ${isDashboard ? '' : '-'}${RADIUS}
a ${RADIUS} ${RADIUS} 0 1 1 0 ${isDashboard ? '-' : ''}${RADIUS * 2}
a ${RADIUS} ${RADIUS} 0 1 1 0 ${isDashboard ? '' : '-'}${RADIUS * 2}
m 0 ${n * RADIUS}
a ${RADIUS} ${RADIUS} 0 1 1 0 ${-2 * n * RADIUS}
a ${RADIUS} ${RADIUS} 0 1 1 0 ${2 * n * RADIUS}
`
}
get trailPathStyle() {
return styleMap({
strokeDasharray: `${this.#perimeter * this.rate}px, ${this.#perimeter}px`,
strokeDashoffset: this.strokeDashoffset
})
}
get strokeDashoffset() {
let offset = (-1 * this.#perimeter * (1 - this.rate)) / 2
return `${offset}px`
}
get rate() {
return this.type === 'dashboard' ? 0.75 : 1
}
get circlePathStyle() {
return styleMap({
strokeDasharray: `${
this.#perimeter * this.rate * (this.value / 100)
}px, ${this.#perimeter}px`,
strokeDashoffset: this.strokeDashoffset,
transition: 'stroke-dasharray 0.6s ease 0s, stroke 0.6s ease'
})
get #dasharray() {
let rate = this.type === TYPE_CIRCLE ? 1 : 0.75
return `${PERIMETER * rate * (this.value / 100)}px, ${PERIMETER}px`
}
#fix(val) {
@ -156,38 +163,37 @@ class Progress extends Component {
}
#drawCircle() {
let offset = OFFSET[this.type]
let dash = DASH_ARRAY[this.type]
let v = this.value
return html`
<svg viewBox="0 0 128 128">
<path
d=${this.trackPath}
stroke="var(--wc-progress-inactive-color, var(--color-plain-2))"
stroke-width="var(--wc-progress-line-width, 6px)"
stroke-linecap="round"
fill="none"
style=${this.trailPathStyle}
d=${this.#path}
stroke="var(--base-color)"
stroke-dashoffset=${offset}
stroke-dasharray=${dash}
/>
<path
d=${this.trackPath}
stroke="var(--wc-progress-active-color, var(--color-teal-1))"
stroke-linecap="round"
stroke-width="var(--wc-progress-line-width, 6px)"
fill="none"
style=${this.circlePathStyle}
d=${this.#path}
opacity=${v > 0 ? '' : 0}
stroke="currentColor"
stroke-dashoffset=${offset}
stroke-dasharray=${this.#dasharray}
/>
<text x="64" y="64">${v}%</text>
</svg>
`
}
#drawLine() {
let v = this.value
return html`
<div class="progress-bar">
<mark
class="thumb"
style=${styleMap({ width: this.value + '%' })}
></mark>
<mark class="thumb" style=${styleMap({ width: v + '%' })}></mark>
</div>
<div class="progress-value" style=${styleMap({ left: this.value + '%' })}>
${this.value + '%'}
<div class="progress-value" style=${styleMap({ left: v + '%' })}>
${v}%
</div>
`
}
@ -196,7 +202,7 @@ class Progress extends Component {
let step = ~~(this.value / 20) || 1
return html`
<main class="container" step=${step}>
${this.type === 'line' ? this.#drawLine() : this.#drawCircle()}
${this.type === TYPE_LINE ? this.#drawLine() : this.#drawCircle()}
</main>
`
}