ui/src/progress/index.js

211 lines
5.0 KiB
JavaScript

/**
* {进度条}
* @author chensbox<chensbox@foxmail.com>
* @date 2023/04/28 16:14:10
*/
import { css, html, Component, styleMap } from 'wkit'
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 = {
value: {
type: Number,
default: 0,
observer(val) {
this.value = this.#fix(val)
}
},
type: TYPE_LINE
}
static styles = [
css`
:host {
display: flex;
}
.container {
position: relative;
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);
}
&[step='2'] {
--wc-progress-active-color: var(--wc-progress-active-color-2);
}
&[step='3'] {
--wc-progress-active-color: var(--wc-progress-active-color-3);
}
&[step='4'] {
--wc-progress-active-color: var(--wc-progress-active-color-4);
}
&[step='5'] {
--wc-progress-active-color: var(--wc-progress-active-color-5);
}
}
`,
// line
css`
:host([type='line']) {
width: 100%;
.progress-value {
display: none;
position: absolute;
z-index: 1;
top: -32px;
margin-left: -24px;
padding: 4px 8px;
border-radius: 4px;
font-size: 14px;
text-align: center;
background: var(--color-dark-2);
color: #fff;
&::after {
display: block;
position: absolute;
left: 50%;
margin-left: -3px;
width: 6px;
height: 6px;
background: var(--color-dark-2);
content: '';
transform: rotate(45deg);
}
}
&:host(:hover) {
.progress-value {
display: block;
}
}
}
.progress-bar {
display: flex;
width: 100%;
height: var(--line-width);
border-radius: 32px;
background: var(--base-color);
.thumb {
width: 0;
height: var(--line-width);
border-radius: 32px;
background: var(--wc-progress-active-color, var(--color-teal-1));
transition: width 0.5s ease;
}
}
`,
// circle & dashboard
css`
:host([type='circle']),
: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.5s ease;
}
text {
font-size: calc(var(--line-width) * 4);
fill: currentColor;
text-anchor: middle;
alignment-baseline: middle;
}
}
`
]
get #path() {
let n = this.type === TYPE_CIRCLE ? -1 : 1
return `
M 64 64
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 #dasharray() {
let rate = this.type === TYPE_CIRCLE ? 1 : 0.75
return `${PERIMETER * rate * (this.value / 100)}px, ${PERIMETER}px`
}
#fix(val) {
return Math.max(0, Math.min(val, 100))
}
#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.#path}
stroke="var(--base-color)"
stroke-dashoffset=${offset}
stroke-dasharray=${dash}
/>
<path
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: v + '%' })}></mark>
</div>
<div class="progress-value" style=${styleMap({ left: v + '%' })}>
${v}%
</div>
`
}
render() {
let step = ~~(this.value / 20) || 1
return html`
<main class="container" step=${step}>
${this.type === TYPE_LINE ? this.#drawLine() : this.#drawCircle()}
</main>
`
}
}
Progress.reg('progress')
百搭WCUI组件库, 基于web components开发。面向下一代的UI组件库
JavaScript 98.9%
CSS 1.1%