UNPKG

isu-elements

Version:

Polymer components for building web apps.

346 lines (321 loc) 10.9 kB
import { html, PolymerElement } from '@polymer/polymer' /** Example: ```html <isu-progress percentage="50" show-text></isu-progress> <isu-progress percentage="100" show-text status="success"></isu-progress> <isu-progress percentage="100" show-text status="warning"></isu-progress> <isu-progress percentage="50" show-text status="exception"></isu-progress> <isu-progress stroke-width="24" percentage="100" show-text status="success"></isu-progress> <isu-progress percentage="20" color="#000" show-text></isu-progress> <isu-progress type="circle" percentage="0" show-text></isu-progress> <isu-progress type="circle" percentage="25" show-text></isu-progress> <isu-progress type="circle" percentage="100" status="success" show-text></isu-progress> <isu-progress type="circle" percentage="70" status="warning" show-text></isu-progress> <isu-progress type="circle" percentage="50" status="exception" show-text></isu-progress> <isu-progress type="dashboard" percentage="0" show-text></isu-progress> <isu-progress type="dashboard" percentage="25" show-text></isu-progress> <isu-progress type="dashboard" percentage="100" status="success" show-text></isu-progress> <isu-progress type="dashboard" percentage="70" status="warning" show-text></isu-progress> <isu-progress type="dashboard" percentage="50" status="exception" show-text></isu-progress> ``` * @customElement * @polymer * @demo demo/isu-progress/index.html */ class IsuProgress extends PolymerElement { static get is () { return 'isu-progress' } static get template () { return html` <style> :host .isu-progress { position: relative; line-height: 1; } :host .isu-progress-bar { padding-right: 50px; width: 100%; margin-right: -55px; box-sizing: border-box; display: inline-block; vertical-align: middle; } :host .isu-progress-bar-outer { height: 6px; border-radius: 100px; background-color: #EBEEF5; overflow: hidden; position: relative; vertical-align: middle; } :host .isu-progress-bar-inner { position: absolute; left: 0; top: 0; height: 100%; background-color: #409EFF; text-align: right; border-radius: 100px; line-height: 1; white-space: nowrap; transition: width .6s ease; } :host .isu-progress-text { font-size: 14px; color: #606266; display: inline-block; vertical-align: middle; margin-left: 10px; line-height: 1; } :host .isu-icon-status { display: inline-block; vertical-align: middle; text-align: center; border-radius: 50%; margin-left: 10px; overflow: hidden; } :host .isu-progress-circle, :host .isu-progress-dashboard { display: inline-block; } :host .isu-progress-circle .isu-progress-text, :host .isu-progress-dashboard .isu-progress-text { position: absolute; top: 50%; left: 0; width: 100%; text-align: center; margin: 0; transform: translate(0,-50%); } :host .isu-progress-circle .isu-icon-status, :host .isu-progress-dashboard .isu-icon-status { margin-left: 0; } </style> <div class$="isu-progress {{getProgressClass(type, status)}}"> <template is="dom-if" if="[[isShowProgress(type, 'line')]]"> <div class="isu-progress-bar"> <div class="isu-progress-bar-outer" style$="[[getOuterBarStyle(strokeWidth)]]"> <div class="isu-progress-bar-inner" style$="[[getInnerBarStyle(percentage)]]"></div> </div> </div> </template> <template is="dom-if" if="[[isShowProgress(type, 'other')]]"> <div class="isu-progress-circle" style$="[[getCircleStyle(width)]]"> <svg viewBox="0 0 100 100"> <path d$="[[trackPath()]]" stroke="#e5e9f2" stroke-width$="[[relativeStrokeWidth]]" fill="none" style$="[[trailPathStyle()]]"></path> <path d$="[[trackPath()]]" stroke$="[[getStrokeColor(color, status)]]" fill="none" stroke-linecap$="round" stroke-width$="[[relativeStrokeWidth]]" style$="[[circlePathStyle()]]"></path> </svg> </div> </template> <template is="dom-if" if="[[showText]]"> <div class="isu-progress-text"> <template is="dom-if" if="[[isShowStatus(status, 'icon')]]"> <span style$="[[getStatusIconStyle(status)]]" class="isu-icon-status">[[getStatusIconText(status)]]</span> </template> <template is="dom-if" if="[[isShowStatus(status, 'text')]]"> <div>[[percentage]]%</div> </template> </div> </template> </div> ` } static get properties () { return { /** * Progress bar type, the value must be one of line, dashboard, circle * @type {string} * @default line */ type: { type: String, value: 'line', observer: 'onTypeChange' }, /** * Progress bar value * @type {Number} * @default 0 */ percentage: { type: Number, value: 0, observer: 'onPercentageChange' }, /** * Progress bar width * @type {Number} * @default 6 */ strokeWidth: { type: Number, value: 6 }, /** * Progress bar, the value must be one of success, exception, warning * @type {string} */ status: { type: String, value: '', observer: 'onStatusChange' }, /** * Progress bar background color * @type {string} */ color: { type: String }, /** * Circular progress bar width * @type {Number} * @default 126 */ width: { type: Number, value: 126 }, /** * Whether to display the progress bar value * @type {Boolean} * @default false */ showText: { type: Boolean, value: false }, relativeStrokeWidth: { type: Number, computed: 'computedWidth(width, strokeWidth)' } } } getProgressClass (type, status) { return `isu-progress-${type} is-${status}` } getStrokeColor (color, status) { const colorMap = { success: '#13ce66', exception: '#ff4949', warning: '#e6a23c' } if (color) { return color } else { return colorMap[status] || '#20a0ff' } } getCircleParameter () { const radius = parseInt(50 - parseFloat(this.relativeStrokeWidth) / 2, 10) const perimeter = 2 * Math.PI * radius const rate = this.type === 'dashboard' ? 0.75 : 1 const strokeDashoffset = -1 * perimeter * (1 - rate) / 2 return { perimeter, rate, strokeDashoffset: `${strokeDashoffset}px` } } trailPathStyle () { const paraObj = this.getCircleParameter() return `stroke-dasharray: ${(paraObj.perimeter * paraObj.rate)}px, ${paraObj.perimeter}px; stroke-dashoffset: ${paraObj.strokeDashoffset}` } circlePathStyle () { const paraObj = this.getCircleParameter() return ` stroke-dasharray: ${paraObj.perimeter * paraObj.rate * (this.percentage / 100)}px, ${paraObj.perimeter}px; stroke-dashoffset: ${paraObj.strokeDashoffset}; transition: stroke-dasharray 0.6s ease 0s, stroke 0.6s ease ` } computedWidth (width, strokeWidth) { return (strokeWidth / width * 100).toFixed(1) } trackPath () { const radius = parseInt(50 - parseFloat(this.relativeStrokeWidth) / 2, 10) 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} ` } getCircleStyle (width) { return `width: ${width}px; height: ${width}px;` } getStatusIconStyle (status) { const width = this.strokeWidth < 14 ? '14' : this.strokeWidth - 6 let style = `width: ${width}px; height: ${width}px; line-height: ${width}px; font-size: ${width}px;` const iconStyleMap = { warning: 'background-color: #e6a23c; color: #fff;', success: 'border: 1px solid #13ce66; color: #13ce66;', exception: 'border: 1px solid #ff4949; color: #ff4949;' } style += iconStyleMap[status] return style } getStatusIconText (status) { const textMap = { warning: '!', success: '✓', exception: 'x' } return textMap[status] } getInnerBarStyle (percentage) { const colorMap = { success: '#13ce66', exception: '#ff4949', warning: '#e6a23c' } const color = this.color ? this.color : colorMap[this.status] return `width: ${percentage}%; background-color: ${color}` } getOuterBarStyle (strokeWidth) { return `height: ${strokeWidth}px` } isShowStatus (status, showType) { const statusArray = ['success', 'exception', 'warning'] return showType === 'icon' ? statusArray.indexOf(status) > -1 : statusArray.indexOf(status) === -1 } isShowProgress (type, showType) { return type === showType || (showType === 'other' && (type === 'circle' || type === 'dashboard')) } onTypeChange (type) { const typeArray = ['line', 'circle', 'dashboard'] if (typeArray.indexOf(type) === -1) { throw new Error('The type value must be one of line, circle, and dashboard.') } } onPercentageChange (percentage) { if (percentage < 0 || percentage > 100) { throw new Error('The percentage value must be between 0 and 100.') } } onStatusChange (status) { const statusArray = ['success', 'exception', 'warning'] if (statusArray.indexOf(status) === -1 && status !== '') { throw new Error('The status value must be one of success, exception, and warning.') } } } window.customElements.define(IsuProgress.is, IsuProgress)