diff --git a/src/form/input.js b/src/form/input.js index cb9265d..bc194ea 100644 --- a/src/form/input.js +++ b/src/form/input.js @@ -140,6 +140,7 @@ class Input extends Component { .list { width: 100%; + background: #fff; } &.hide { display: none; diff --git a/src/progress/index.js b/src/progress/index.js new file mode 100644 index 0000000..82cf453 --- /dev/null +++ b/src/progress/index.js @@ -0,0 +1,310 @@ +/** + * {进度条} + * @author chensbox + * @date 2023/04/28 16:14:10 + */ + +import { css, html, Component, styleMap, svg } from '@bd/core' + +class Progress extends Component { + static props = { + value: { + type: Number, + default: 0, + attribute: false, + observer(val) { + this.value = this.clamp(val) + } + }, + type: { + type: String, + default: 'line' // line/circle/dashboard + }, + 'stroke-width': { + type: Number, + default: 6, + attribute: false + }, + 'text-inside': { + type: Boolean, + default: false, + attribute: true + }, + status: { + type: String, + default: '', // success/exception/warning + attribute: false + }, + color: { + type: String, + default: '', + attribute: false, + observer(val) { + if (val.includes(',')) { + this.#colors = val.split(',') + } else { + this.#colors = val + } + } + }, + width: { + type: Number, + default: 126, + attribute: false + }, + 'show-text': { + type: Boolean, + default: false, + attribute: true + }, + + format: { + type: Function, + default: null, + attribute: false + }, + 'back-color': { + type: String, + default: '#ebeef5', + attribute: false + }, + 'text-color': { + type: String, + default: '#606266', + attribute: false + }, + 'stroke-linecap': { + type: String, + default: 'round', //butt/round/square + attribute: false + } + } + + static styles = [ + css` + :host { + position: relative; + display: inline-block; + } + :host([type='line']) { + width: 100%; + .progress-text { + width: auto; + margin-left: 5px; + display: inline-block; + } + } + .progress-bar { + display: inline-block; + vertical-align: middle; + } + .bar-outer, + .bar-inner { + height: 100%; + border-radius: 999rem; + } + .bar-inner { + transition: 0.6s ease; + transition-property: width, background-color; + .bar-innerText { + margin: 0 5px; + height: 100%; + line-height: 6px; + font-size: 12px; + line-height: 100%; + vertical-align: middle; + text-align: right; + } + } + .progress-text { + display: block; + position: absolute; + width: 100%; + top: 50%; + transform: translateY(-50%); + text-align: center; + } + ` + ] + + #colors + + get relativeStrokeWidth() { + return ((this['stroke-width'] / this.width) * 100).toFixed(1) + } + get radius() { + if (this.type === 'circle' || this.type === 'dashboard') { + return parseInt(50 - parseFloat(this.relativeStrokeWidth) / 2, 10) + } else { + return 0 + } + } + get trackPath() { + const radius = this.radius + const isDashboard = this.type === 'dashboard' + return ` + M 50 50 + m 0 ${isDashboard ? '' : '-'}${radius} + a ${radius} ${radius} 0 1 1 0 ${isDashboard ? '-' : ''}${radius * 2} + a ${radius} ${radius} 0 1 1 0 ${isDashboard ? '' : '-'}${radius * 2} + ` + } + get trailPathStyle() { + return styleMap({ + strokeDasharray: `${this.perimeter * this.rate}px, ${this.perimeter}px`, + strokeDashoffset: this.strokeDashoffset + }) + } + get strokeDashoffset() { + const offset = (-1 * this.perimeter * (1 - this.rate)) / 2 + return `${offset}px` + } + get perimeter() { + return 2 * Math.PI * this.radius + } + get rate() { + return this.type === 'dashboard' ? 0.75 : 1 + } + get stroke() { + let ret + if (this.color) { + ret = this.getCurrentColor(this.value) + } else { + switch (this.status) { + case 'success': + ret = '#13ce66' + break + case 'exception': + ret = '#ff4949' + break + case 'warning': + ret = '#e6a23c' + break + default: + ret = '#20a0ff' + } + } + return ret + } + 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 barStyle() { + return styleMap({ + width: this.value + '%', + 'background-color': this.stroke //this.getCurrentColor(this.value) + }) + } + get progressTextSize() { + let size = + this.type === 'line' + ? 12 + this['stroke-width'] * 0.4 + : this.width * 0.111111 + 2 + return size + 'px' + } + + clamp(val) { + return Math.max(0, Math.min(val, 100)) + } + getCurrentColor(value) { + if (!Array.isArray(this.#colors)) { + return this.#colors + } + let length = this.#colors.length + let step = 100 / length + let index = Math.floor(value / step) + + return this.#colors[index >= length ? length - 1 : index] + } + + renderCircle() { + return html` +
+ + + + +
+ ` + } + renderLine() { + let $barInnerText = '' + if (this['text-inside'] && this['show-text']) { + $barInnerText = html` +
+ ${this.value + '%'} +
+ ` + } + + return html` +
+
+
${$barInnerText}
+
+
+ ` + } + render() { + let $outSideText = '' + if (this['show-text'] && !this['text-inside']) { + $outSideText = html` +
+ ${this.value + '%'} +
+ ` + } + + return html` + ${this.type === 'line' ? this.renderLine() : this.renderCircle()} + ${$outSideText} + ` + } +} + +Progress.reg('progress')