进度条组件完成重构
parent
3da409d97c
commit
15757f9f7a
|
@ -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>
|
||||
`
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue