进度条组件完成重构

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