v 1.1.0
30
src/App.vue
@ -1,30 +0,0 @@
|
||||
<template>
|
||||
<div id="app" ref="data-root">
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'app'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
#app {
|
||||
font-family:
|
||||
'-apple-system',
|
||||
'BlinkMacSystemFont',
|
||||
'Helvetica Neue',
|
||||
'PingFang SC',
|
||||
'Microsoft YaHei',
|
||||
'Source Han Sans SC',
|
||||
'Noto Sans CJK SC',
|
||||
'WenQuanYi Micro Hei',
|
||||
'sans-serif';
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 855 KiB |
@ -1,12 +0,0 @@
|
||||
.text-info {
|
||||
font-size: 17px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 20px;
|
||||
text-indent: 20px;
|
||||
font-weight: bold;
|
||||
line-height: 30px;
|
||||
margin: 10px 0px;
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
@font-face{
|
||||
font-family: 'code';
|
||||
src: url('../font/code.ttf');
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
@import url('./font.less');
|
||||
@import url('./class.less');
|
||||
|
||||
* {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
html, body{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
<template>
|
||||
<div class="highlight-code">
|
||||
<pre><code :ref="ref">
|
||||
<slot></slot>
|
||||
</code></pre>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import 'highlight.js/styles/monokai-sublime.css'
|
||||
|
||||
import highlight from 'highlight.js/lib/highlight'
|
||||
|
||||
import xml from 'highlight.js/lib/languages/xml'
|
||||
import javascript from 'highlight.js/lib/languages/javascript'
|
||||
|
||||
highlight.registerLanguage('xml', xml)
|
||||
highlight.registerLanguage('javascript', javascript)
|
||||
|
||||
export default {
|
||||
name: 'HighlightCode',
|
||||
data () {
|
||||
return {
|
||||
ref: `highlight-code-${(new Date()).getTime()}`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const { ref, $refs } = this
|
||||
|
||||
const codeChunk = $refs[ref]
|
||||
|
||||
highlight.highlightBlock(codeChunk)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.highlight-code {
|
||||
|
||||
code {
|
||||
font-family: 'code';
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,8 +0,0 @@
|
||||
import highlightCode from './highlightCode'
|
||||
|
||||
import sideNav from './sideNav'
|
||||
|
||||
export default function (Vue) {
|
||||
Vue.component('highlightCode', highlightCode)
|
||||
Vue.component('sideNav', sideNav)
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
<template>
|
||||
<div class="side-nav">
|
||||
<div class="item" v-for="navItem in nav" :key="navItem.title">
|
||||
<a :href="`#${navItem.target}`">{{ navItem.title }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SideNav',
|
||||
props: ['nav']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.side-nav {
|
||||
position: fixed;
|
||||
width: 200px;
|
||||
left: 20px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
|
||||
.item {
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
font-size: 18px;
|
||||
|
||||
a {
|
||||
color: #fff;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:visited {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,358 +0,0 @@
|
||||
<template>
|
||||
<div class="arc-ring-chart">
|
||||
<loading v-if="!data" />
|
||||
|
||||
<div class="label-line" v-else>
|
||||
<div class="label-item" v-for="(label, i) in data.data" :key="label.title">
|
||||
<div :style="`background-color: ${data.color[i % data.color.length]};`"></div>
|
||||
<div>{{ label.title }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<canvas :ref="ref" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ArcRingChart',
|
||||
props: ['data'],
|
||||
data () {
|
||||
return {
|
||||
ref: `concentric-arc-chart-${(new Date()).getTime()}`,
|
||||
canvasDom: '',
|
||||
canvasWH: [0, 0],
|
||||
ctx: '',
|
||||
|
||||
arcOriginPos: [],
|
||||
|
||||
defaultDecorationCircleRadius: 0.65,
|
||||
defaultArcRadiusArea: [0.3, 0.4],
|
||||
defaultArcWidthArea: [2, 10],
|
||||
defaultLabelFontSize: 12,
|
||||
|
||||
decorationRadius: '',
|
||||
|
||||
radianOffset: Math.PI / -2,
|
||||
|
||||
totalValue: 0,
|
||||
|
||||
arcRadius: [],
|
||||
arcRadian: [],
|
||||
arcWidth: [],
|
||||
|
||||
labelLinePoints: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
data (d) {
|
||||
const { draw } = this
|
||||
|
||||
d && draw()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const { $nextTick, initCanvas, calcArcConfig, data, draw } = this
|
||||
|
||||
$nextTick(e => {
|
||||
initCanvas()
|
||||
|
||||
calcArcConfig()
|
||||
|
||||
data && draw()
|
||||
})
|
||||
},
|
||||
initCanvas () {
|
||||
const { $refs, ref, labelRef, canvasWH } = this
|
||||
|
||||
const canvas = this.canvasDom = $refs[ref]
|
||||
|
||||
this.labelDom = $refs[labelRef]
|
||||
|
||||
canvasWH[0] = canvas.clientWidth
|
||||
canvasWH[1] = canvas.clientHeight
|
||||
|
||||
canvas.setAttribute('width', canvasWH[0])
|
||||
canvas.setAttribute('height', canvasWH[1])
|
||||
|
||||
this.ctx = canvas.getContext('2d')
|
||||
},
|
||||
calcArcConfig () {
|
||||
const { canvasWH, arcOriginPos } = this
|
||||
|
||||
arcOriginPos[0] = canvasWH[0] / 2
|
||||
arcOriginPos[1] = canvasWH[1] / 2
|
||||
},
|
||||
draw () {
|
||||
const { ctx, canvasWH, drawDecorationCircle } = this
|
||||
|
||||
ctx.clearRect(0, 0, ...canvasWH)
|
||||
|
||||
drawDecorationCircle()
|
||||
|
||||
const { calcArcRadius, calcArcRadian, calcArcWidth, drawArc } = this
|
||||
|
||||
calcArcRadius()
|
||||
|
||||
calcArcRadian()
|
||||
|
||||
calcArcWidth()
|
||||
|
||||
drawArc()
|
||||
|
||||
const { calcLableLinePoints, drawLabelLine, drawLabelText } = this
|
||||
|
||||
calcLableLinePoints()
|
||||
|
||||
drawLabelLine()
|
||||
|
||||
drawLabelText()
|
||||
},
|
||||
drawDecorationCircle () {
|
||||
const { ctx, data: { decorationCircleRadius }, defaultDecorationCircleRadius, arcOriginPos } = this
|
||||
|
||||
const radius = this.decorationRadius = Math.min(...arcOriginPos) * (decorationCircleRadius || defaultDecorationCircleRadius)
|
||||
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.strokeStyle = 'rgba(250, 250, 250, 0.2)'
|
||||
|
||||
ctx.lineWidth = 4
|
||||
|
||||
ctx.arc(...arcOriginPos, radius, 0, Math.PI * 2)
|
||||
|
||||
ctx.stroke()
|
||||
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.lineWidth = 1
|
||||
|
||||
ctx.arc(...arcOriginPos, radius - 7, 0, Math.PI * 2)
|
||||
|
||||
ctx.closePath()
|
||||
|
||||
ctx.stroke()
|
||||
},
|
||||
calcArcRadius () {
|
||||
const { data: { data, arcRadiusArea }, defaultArcRadiusArea, arcOriginPos, randomExtend } = this
|
||||
|
||||
const fullRadius = Math.min(...arcOriginPos)
|
||||
|
||||
const currentArcRaidusArea = arcRadiusArea || defaultArcRadiusArea
|
||||
|
||||
const maxRadius = fullRadius * Math.max(...currentArcRaidusArea)
|
||||
const minRadius = fullRadius * Math.min(...currentArcRaidusArea)
|
||||
|
||||
this.arcRadius = data.map(t => randomExtend(minRadius, maxRadius))
|
||||
},
|
||||
calcArcRadian () {
|
||||
const { data: { data }, multipleSum, radianOffset } = this
|
||||
|
||||
const valueSum = this.totalValue = multipleSum(...data.map(({ value }) => value))
|
||||
|
||||
let radian = radianOffset
|
||||
|
||||
const fullRadian = Math.PI * 2
|
||||
|
||||
const avgRadian = fullRadian / data.length
|
||||
|
||||
this.arcRadian = data.map(({ value }) => {
|
||||
const valueRadian = valueSum === 0 ? avgRadian : value / valueSum * fullRadian
|
||||
|
||||
return [radian, (radian += valueRadian)]
|
||||
})
|
||||
},
|
||||
calcArcWidth () {
|
||||
const { data: { data, arcWidthArea }, defaultArcWidthArea, randomExtend } = this
|
||||
|
||||
const currentArea = arcWidthArea || defaultArcWidthArea
|
||||
|
||||
const maxWidth = Math.max(...currentArea)
|
||||
const minWidth = Math.min(...currentArea)
|
||||
|
||||
this.arcWidth = data.map(t => randomExtend(minWidth, maxWidth))
|
||||
},
|
||||
drawArc () {
|
||||
const { ctx, arcRadius, arcRadian, arcWidth, data: { color }, arcOriginPos } = this
|
||||
|
||||
const colorNum = color.length
|
||||
|
||||
arcRadius.forEach((radius, i) => {
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.arc(...arcOriginPos, radius, ...arcRadian[i])
|
||||
|
||||
ctx.strokeStyle = color[i % colorNum]
|
||||
|
||||
ctx.lineWidth = arcWidth[i]
|
||||
|
||||
ctx.stroke()
|
||||
})
|
||||
},
|
||||
calcLableLinePoints () {
|
||||
const { arcRadian, arcRadius, arcOriginPos: [x, y], totalValue } = this
|
||||
|
||||
const { canvas: { getCircleRadianPoint }, data: { data } } = this
|
||||
|
||||
let [leftlabelLineNum, rightLabelLineNum] = [0, 0]
|
||||
|
||||
const arcMiddlePoints = arcRadian.map((radian, i) => {
|
||||
const middleRadian = (radian[1] - radian[0]) / 2 + radian[0]
|
||||
|
||||
const point = getCircleRadianPoint(x, y, arcRadius[i], middleRadian)
|
||||
|
||||
point[0] > x && (data[i].value || !totalValue) && rightLabelLineNum++
|
||||
point[0] <= x && (data[i].value || !totalValue) && leftlabelLineNum++
|
||||
|
||||
return point
|
||||
})
|
||||
|
||||
const { getYPos, decorationRadius } = this
|
||||
|
||||
const labelLineYArea = [y - decorationRadius + 10, y + decorationRadius - 10]
|
||||
|
||||
const leftYPos = getYPos(labelLineYArea, leftlabelLineNum)
|
||||
const rightYPos = getYPos(labelLineYArea, rightLabelLineNum)
|
||||
|
||||
const offsetX = decorationRadius + 10
|
||||
|
||||
const leftlabelLineEndX = x - offsetX
|
||||
const rightLableLineEndX = x + offsetX
|
||||
|
||||
const maxRadius = Math.max(...arcRadius)
|
||||
|
||||
const leftNearRadiusX = x - maxRadius - 8
|
||||
const rightNearRadiusX = x + maxRadius + 8
|
||||
|
||||
this.labelLinePoints = arcMiddlePoints.map(([px, py], i) => {
|
||||
if (!data[i].value && totalValue) return [false, false, false, false]
|
||||
|
||||
if (px > x) {
|
||||
const yPos = rightYPos.shift()
|
||||
|
||||
return [
|
||||
[px, py],
|
||||
[rightNearRadiusX, py],
|
||||
[rightLableLineEndX - 10, yPos],
|
||||
[rightLableLineEndX, yPos]
|
||||
]
|
||||
} else {
|
||||
const yPos = leftYPos.pop()
|
||||
|
||||
return [
|
||||
[px, py],
|
||||
[leftNearRadiusX, py],
|
||||
[leftlabelLineEndX + 10, yPos],
|
||||
[leftlabelLineEndX, yPos]
|
||||
]
|
||||
}
|
||||
})
|
||||
},
|
||||
getYPos (area, num) {
|
||||
let gap = 0
|
||||
|
||||
const minus = area[1] - area[0]
|
||||
|
||||
if (num === 1) {
|
||||
return [area[0] + minus / 2]
|
||||
} else if (num === 2) {
|
||||
const offset = minus * 0.1
|
||||
|
||||
return [area[0] + offset, area[1] - offset]
|
||||
} else {
|
||||
gap = minus / (num - 1)
|
||||
|
||||
return new Array(num).fill(0).map((t, i) => area[0] + i * gap)
|
||||
}
|
||||
},
|
||||
drawLabelLine () {
|
||||
const { ctx, labelLinePoints, canvas: { drawPolyline }, data: { color } } = this
|
||||
|
||||
const colorNum = color.length
|
||||
|
||||
labelLinePoints.forEach((polyline, i) =>
|
||||
polyline[0] && drawPolyline(ctx, polyline, 2, color[i % colorNum], false, [10, 0], true))
|
||||
},
|
||||
drawLabelText () {
|
||||
const { ctx, labelLinePoints, data: { data, labelFontSize, fixed }, totalValue, defaultLabelFontSize, arcOriginPos: [x] } = this
|
||||
|
||||
ctx.font = `${labelFontSize || defaultLabelFontSize}px Arial`
|
||||
|
||||
ctx.fillStyle = '#fff'
|
||||
|
||||
let totalPercent = 0
|
||||
|
||||
const dataLast = data.length - 1
|
||||
|
||||
data.forEach(({ value, title }, i) => {
|
||||
if (!value && totalValue) return
|
||||
|
||||
let currentPercent = (value / totalValue * 100).toFixed(fixed || 1)
|
||||
|
||||
i === dataLast && (currentPercent = (100 - totalPercent).toFixed(fixed || 1))
|
||||
|
||||
!totalValue && (currentPercent = 0)
|
||||
|
||||
const textPos = labelLinePoints[i][2]
|
||||
|
||||
const isLeft = textPos[0] < x
|
||||
|
||||
ctx.textAlign = isLeft ? 'end' : 'start'
|
||||
|
||||
ctx.textBaseline = 'bottom'
|
||||
|
||||
ctx.fillText(`${currentPercent}%`, ...textPos)
|
||||
|
||||
ctx.textBaseline = 'top'
|
||||
|
||||
ctx.fillText(title, ...textPos)
|
||||
|
||||
totalPercent += Number(currentPercent)
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.arc-ring-chart {
|
||||
position: relative;
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.label-line {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
font-size: 10px;
|
||||
|
||||
.label-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 0px 3px;
|
||||
height: 20px;
|
||||
align-items: center;
|
||||
|
||||
:nth-child(1) {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 93 KiB |
@ -1,54 +0,0 @@
|
||||
<template>
|
||||
<div class="border-box-1">
|
||||
<img class="flash-left-top" src="./img/border.gif">
|
||||
<img class="flash-right-top" src="./img/border.gif">
|
||||
<img class="flash-left-bottom" src="./img/border.gif">
|
||||
<img class="flash-right-bottom" src="./img/border.gif">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BorderBox1'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.border-box-1 {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
min-width: 300px;
|
||||
min-height: 300px;
|
||||
padding: 35px;
|
||||
overflow: hidden;
|
||||
|
||||
.flash-left-top, .flash-right-top, .flash-left-bottom, .flash-right-bottom {
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.flash-left-top {
|
||||
top: 0px;
|
||||
left: -70px;
|
||||
}
|
||||
|
||||
.flash-right-top {
|
||||
top: 0px;
|
||||
right: -70px;
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
.flash-left-bottom {
|
||||
bottom: 0px;
|
||||
left: -70px;
|
||||
transform: rotateX(180deg);
|
||||
}
|
||||
|
||||
.flash-right-bottom {
|
||||
bottom: 0px;
|
||||
right: -70px;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 549 B |
@ -1,20 +0,0 @@
|
||||
<template>
|
||||
<div class="border-box-2">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BorderBox2'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.border-box-2 {
|
||||
box-sizing: border-box;
|
||||
border-style: solid;
|
||||
border-image: url('./img/border.png') 14 fill;
|
||||
border-width: 14px;
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 1.0 KiB |
@ -1,20 +0,0 @@
|
||||
<template>
|
||||
<div class="border-box-3">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BorderBox3'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.border-box-3 {
|
||||
box-sizing: border-box;
|
||||
border-style: solid;
|
||||
border-image: url('./img/border.png') 17 24 18 19 fill;
|
||||
border-width: 24px;
|
||||
}
|
||||
</style>
|
@ -1,142 +0,0 @@
|
||||
<template>
|
||||
<div class="border-box-4" :ref="ref">
|
||||
<svg :class="`border-svg-container ${reverse && 'reverse'}`">
|
||||
<polyline class="line-1" :points="`145, ${height - 5} 40, ${height - 5} 10, ${height - 35}
|
||||
10, 40 40, 5 150, 5 170, 20 ${width - 15}, 20`"/>
|
||||
<polyline class="line-2" :points="`245, ${height - 1} 36, ${height - 1} 14, ${height - 23}
|
||||
14, ${height - 100}`" />
|
||||
<polyline class="line-3" :points="`7, ${height - 40} 7, ${height - 75}`" />
|
||||
<polyline class="line-4" :points="`28, 24 13, 41 13, 64`" />
|
||||
<polyline class="line-5" :points="`5, 45 5, 140`" />
|
||||
<polyline class="line-6" :points="`14, 75 14, 180`" />
|
||||
<polyline class="line-7" :points="`55, 11 147, 11 167, 26 250, 26`" />
|
||||
<polyline class="line-8" :points="`158, 5 173, 16`" />
|
||||
<polyline class="line-9" :points="`200, 17 ${width - 10}, 17`" />
|
||||
<polyline class="line-10" :points="`385, 17 ${width - 10}, 17`" />
|
||||
</svg>
|
||||
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BorderBox4',
|
||||
data () {
|
||||
return {
|
||||
ref: `border-box-4-${(new Date()).getTime()}`,
|
||||
width: 0,
|
||||
height: 0
|
||||
}
|
||||
},
|
||||
props: ['reverse'],
|
||||
methods: {
|
||||
init () {
|
||||
const { $nextTick, $refs, ref } = this
|
||||
|
||||
$nextTick(e => {
|
||||
this.width = $refs[ref].clientWidth
|
||||
this.height = $refs[ref].clientHeight
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.border-box-4 {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
padding: 30px;
|
||||
|
||||
.reverse {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.border-svg-container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
|
||||
polyline {
|
||||
fill: none;
|
||||
}
|
||||
}
|
||||
|
||||
.sred {
|
||||
stroke: red;
|
||||
}
|
||||
|
||||
.sblue {
|
||||
stroke: fade(blue, 80);
|
||||
}
|
||||
|
||||
.sw1 {
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.sw3 {
|
||||
stroke-width: 3px;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
|
||||
.line-1 {
|
||||
.sred;
|
||||
.sw1;
|
||||
}
|
||||
|
||||
.line-2 {
|
||||
.sblue;
|
||||
.sw1;
|
||||
}
|
||||
|
||||
.line-3 {
|
||||
.sred;
|
||||
.sw3;
|
||||
}
|
||||
|
||||
.line-4 {
|
||||
.sred;
|
||||
.sw3;
|
||||
}
|
||||
|
||||
.line-5 {
|
||||
.sred;
|
||||
.sw1;
|
||||
}
|
||||
|
||||
.line-6 {
|
||||
.sblue;
|
||||
.sw1;
|
||||
}
|
||||
|
||||
.line-7 {
|
||||
.sblue;
|
||||
.sw1;
|
||||
}
|
||||
|
||||
.line-8 {
|
||||
.sblue;
|
||||
.sw3;
|
||||
}
|
||||
|
||||
.line-9 {
|
||||
.sred;
|
||||
.sw3;
|
||||
stroke-dasharray: 100 250;
|
||||
}
|
||||
|
||||
.line-10 {
|
||||
.sblue;
|
||||
.sw1;
|
||||
stroke-dasharray: 80 270;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,89 +0,0 @@
|
||||
<template>
|
||||
<div class="border-box-5" :ref="ref">
|
||||
<svg :class="`svg-container ${reverse && 'reverse'}`">
|
||||
<polyline class="line-1" :points="`8, 5 ${width - 5}, 5 ${width - 5}, ${height - 100}
|
||||
${width - 100}, ${height - 5} 8, ${height - 5} 8, 5`" />
|
||||
<polyline class="line-2" :points="`3, 5 ${width - 20}, 5 ${width - 20}, ${height - 60}
|
||||
${width - 74}, ${height - 5} 3, ${height - 5} 3, 5`" />
|
||||
<polyline class="line-3" :points="`50, 13 ${width - 35}, 13`" />
|
||||
<polyline class="line-4" :points="`15, 20 ${width - 35}, 20`" />
|
||||
<polyline class="line-5" :points="`15, ${height - 20} ${width - 110}, ${height - 20}`" />
|
||||
<polyline class="line-6" :points="`15, ${height - 13} ${width - 110}, ${height - 13}`" />
|
||||
</svg>
|
||||
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BorderBox5',
|
||||
data () {
|
||||
return {
|
||||
ref: `border-box-5-${(new Date()).getTime()}`,
|
||||
width: 0,
|
||||
height: 0
|
||||
}
|
||||
},
|
||||
props: ['reverse'],
|
||||
methods: {
|
||||
init () {
|
||||
const { $nextTick, $refs, ref } = this
|
||||
|
||||
$nextTick(e => {
|
||||
this.width = $refs[ref].clientWidth
|
||||
this.height = $refs[ref].clientHeight
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.border-box-5 {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
|
||||
.reverse {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.svg-container {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
polyline {
|
||||
fill: none;
|
||||
}
|
||||
}
|
||||
|
||||
.line-1 {
|
||||
stroke-width: 1;
|
||||
stroke: fade(#fff, 35);
|
||||
}
|
||||
|
||||
.line-2 {
|
||||
stroke: fade(#fff, 20);
|
||||
}
|
||||
|
||||
.line-3, .line-6 {
|
||||
stroke-width: 5;
|
||||
stroke: fade(#fff, 15);
|
||||
}
|
||||
|
||||
.line-4, .line-5 {
|
||||
stroke-width: 2;
|
||||
stroke: fade(#fff, 15);
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
@ -1,78 +0,0 @@
|
||||
<template>
|
||||
<div class="border-box-6" :ref="ref">
|
||||
<svg class="svg-container">
|
||||
<circle cx="5" cy="5" r="2"/>
|
||||
<circle :cx="width - 5" cy="5" r="2" />
|
||||
<circle :cx="width - 5" :cy="height - 5" r="2" />
|
||||
<circle cx="5" :cy="height - 5" r="2" />
|
||||
<polyline :points="`10, 4 ${width - 10}, 4`" />
|
||||
<polyline :points="`10, ${height - 4} ${width - 10}, ${height - 4}`" />
|
||||
<polyline :points="`5, 70 5, ${height - 70}`" />
|
||||
<polyline :points="`${width - 5}, 70 ${width - 5}, ${height - 70}`" />
|
||||
<polyline :points="`3, 10, 3, 50`" />
|
||||
<polyline :points="`7, 30 7, 80`" />
|
||||
<polyline :points="`${width - 3}, 10 ${width - 3}, 50`" />
|
||||
<polyline :points="`${width - 7}, 30 ${width - 7}, 80`" />
|
||||
<polyline :points="`3, ${height - 10} 3, ${height - 50}`" />
|
||||
<polyline :points="`7, ${height - 30} 7, ${height - 80}`" />
|
||||
<polyline :points="`${width - 3}, ${height - 10} ${width - 3}, ${height - 50}`" />
|
||||
<polyline :points="`${width - 7}, ${height - 30} ${width - 7}, ${height - 80}`" />
|
||||
</svg>
|
||||
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BorderBox6',
|
||||
data () {
|
||||
return {
|
||||
ref: `border-box-6-${(new Date()).getTime()}`,
|
||||
width: 0,
|
||||
height: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const { $nextTick, $refs, ref } = this
|
||||
|
||||
$nextTick(e => {
|
||||
this.width = $refs[ref].clientWidth
|
||||
this.height = $refs[ref].clientHeight
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.border-box-6 {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
|
||||
.svg-container {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
circle {
|
||||
fill: gray;
|
||||
}
|
||||
|
||||
polyline {
|
||||
fill: none;
|
||||
stroke-width: 1;
|
||||
stroke: fade(#fff, 35);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,80 +0,0 @@
|
||||
<template>
|
||||
<div class="border-box-7" :ref="ref">
|
||||
<svg class="svg-container">
|
||||
<polyline class="line-width-2" :points="`0, 25 0, 0 25, 0`" />
|
||||
<polyline class="line-width-2" :points="`${width - 25}, 0 ${width}, 0 ${width}, 25`" />
|
||||
<polyline class="line-width-2" :points="`${width - 25}, ${height} ${width}, ${height} ${width}, ${height - 25}`" />
|
||||
<polyline class="line-width-2" :points="`0, ${height - 25} 0, ${height} 25, ${height}`" />
|
||||
|
||||
<polyline class="line-width-5" :points="`0, 10 0, 0 10, 0`" />
|
||||
<polyline class="line-width-5" :points="`${width - 10}, 0 ${width}, 0 ${width}, 10`" />
|
||||
<polyline class="line-width-5" :points="`${width - 10}, ${height} ${width}, ${height} ${width}, ${height - 10}`" />
|
||||
<polyline class="line-width-5" :points="`0, ${height - 10} 0, ${height} 10, ${height}`" />
|
||||
</svg>
|
||||
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BorderBox7',
|
||||
data () {
|
||||
return {
|
||||
ref: `border-box-7-${(new Date()).getTime()}`,
|
||||
width: 0,
|
||||
height: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const { $nextTick, $refs, ref } = this
|
||||
|
||||
$nextTick(e => {
|
||||
this.width = $refs[ref].clientWidth
|
||||
this.height = $refs[ref].clientHeight
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@color: fade(gray, 30);
|
||||
|
||||
.border-box-7 {
|
||||
position: relative;
|
||||
box-shadow: inset 0 0 40px fade(@color, 30);
|
||||
box-sizing: border-box;
|
||||
border: 1px solid @color;
|
||||
padding: 10px;
|
||||
|
||||
.svg-container {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
polyline {
|
||||
fill: none;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
}
|
||||
|
||||
.line-width-2 {
|
||||
stroke: @color;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.line-width-5 {
|
||||
stroke: fade(gray, 50);
|
||||
stroke-width: 5;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,150 +0,0 @@
|
||||
<template>
|
||||
<div class="capsule-chart">
|
||||
|
||||
<loading v-if="!data" />
|
||||
|
||||
<template v-else>
|
||||
<div class="label-column">
|
||||
<div v-for="item in data.data" :key="item.title">{{ item.title }}</div>
|
||||
<div> </div>
|
||||
</div>
|
||||
|
||||
<div class="capsule-container">
|
||||
<div class="capsule-item" v-for="(capsule, index) in capsuleData" :key="index">
|
||||
<div :style="`width: ${capsule * 100}%; background-color: ${data.color[index % data.data.length]};`"></div>
|
||||
</div>
|
||||
<div class="unit-label">
|
||||
<div class="unit-container">
|
||||
<div v-for="(unit, index) in unitData" :key="unit + index">{{ unit }}</div>
|
||||
</div>
|
||||
<div class="unit-text">单位</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="for-solt">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'CapsuleChart',
|
||||
props: ['data'],
|
||||
data () {
|
||||
return {
|
||||
capsuleData: [],
|
||||
unitData: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
data () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const { data, calcCapsuleAndUnitData } = this
|
||||
|
||||
if (!data) return
|
||||
|
||||
calcCapsuleAndUnitData()
|
||||
},
|
||||
calcCapsuleAndUnitData () {
|
||||
const { data: { data } } = this
|
||||
|
||||
const capsuleData = data.map(({ value }) => value)
|
||||
|
||||
const maxValue = Math.max(...capsuleData)
|
||||
|
||||
this.capsuleData = capsuleData.map(v => maxValue ? v / maxValue : 0)
|
||||
|
||||
const oneSixth = maxValue / 5
|
||||
|
||||
this.unitData = new Array(6).fill(0).map((v, i) => Math.ceil(i * oneSixth))
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.capsule-chart {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
|
||||
.label-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding-right: 10px;
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
|
||||
div {
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.capsule-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.capsule-item {
|
||||
box-shadow: 0 0 3px #999;
|
||||
height: 10px;
|
||||
margin: 5px 0px;
|
||||
border-radius: 5px;
|
||||
width: calc(~"100% - 50px");
|
||||
|
||||
div {
|
||||
height: 8px;
|
||||
margin-top: 1px;
|
||||
border-radius: 5px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
}
|
||||
|
||||
.unit-label {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
line-height: 20px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.unit-text {
|
||||
width: 40px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.unit-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.for-solt {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,607 +0,0 @@
|
||||
<template>
|
||||
<div class="column-chart">
|
||||
<loading v-if="!data" />
|
||||
|
||||
<div class="canvas-container">
|
||||
<canvas :ref="ref" />
|
||||
</div>
|
||||
|
||||
<label-line :label="data.labelLine" :colors="drawColors" />
|
||||
|
||||
<for-slot><slot></slot></for-slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import colorsMixin from '../../mixins/colorsMixin.js'
|
||||
|
||||
import canvasMixin from '../../mixins/canvasMixin.js'
|
||||
|
||||
import axisMixin from '../../mixins/axisMixin.js'
|
||||
|
||||
export default {
|
||||
name: 'ColumnChart',
|
||||
mixins: [colorsMixin, canvasMixin, axisMixin],
|
||||
props: ['data', 'colors'],
|
||||
data () {
|
||||
return {
|
||||
ref: `radar-chart-${(new Date()).getTime()}`,
|
||||
|
||||
// axis base config
|
||||
boundaryGap: true,
|
||||
mulValueAdd: true,
|
||||
horizon: false,
|
||||
|
||||
echelonOffset: 10,
|
||||
defaultColumnBGColor: 'rgba(100, 100, 100, 0.2)',
|
||||
|
||||
defaultValueFontSize: 10,
|
||||
defaultValueColor: '#999',
|
||||
|
||||
columnData: [],
|
||||
columnItemSeriesNum: 0,
|
||||
columnItemAllWidth: 0,
|
||||
columnItemWidth: 0,
|
||||
columnBGWidth: 0,
|
||||
columnItemOffset: [],
|
||||
|
||||
valueTextOffset: [],
|
||||
|
||||
valuePointPos: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
data (d) {
|
||||
const { draw } = this
|
||||
|
||||
d && draw()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async init () {
|
||||
const { initCanvas, initColors } = this
|
||||
|
||||
await initCanvas()
|
||||
|
||||
initColors()
|
||||
|
||||
const { data, draw } = this
|
||||
|
||||
data && draw()
|
||||
},
|
||||
draw () {
|
||||
const { clearCanvas } = this
|
||||
|
||||
clearCanvas()
|
||||
|
||||
const { calcHorizon, initAxis, drawAxis } = this
|
||||
|
||||
calcHorizon()
|
||||
|
||||
initAxis()
|
||||
|
||||
drawAxis()
|
||||
|
||||
const { switchNormalOrCenterOriginType } = this
|
||||
|
||||
switchNormalOrCenterOriginType()
|
||||
},
|
||||
calcHorizon () {
|
||||
const { data: { horizon } } = this
|
||||
|
||||
this.horizon = horizon
|
||||
},
|
||||
switchNormalOrCenterOriginType () {
|
||||
const { centerOrigin, drawNormalTypeColumnChart, drawCenterOriginTypeColumnChart } = this
|
||||
|
||||
if (centerOrigin) drawCenterOriginTypeColumnChart()
|
||||
|
||||
if (!centerOrigin) drawNormalTypeColumnChart()
|
||||
},
|
||||
drawNormalTypeColumnChart () {
|
||||
const { calcColumnConfig, calcColumnItemOffset, calcValuePointPos } = this
|
||||
|
||||
calcColumnConfig()
|
||||
|
||||
calcColumnItemOffset()
|
||||
|
||||
calcValuePointPos()
|
||||
|
||||
const { drawColumnBG, drawFigure, drawValueText } = this
|
||||
|
||||
drawColumnBG()
|
||||
|
||||
drawFigure()
|
||||
|
||||
drawValueText()
|
||||
},
|
||||
calcColumnConfig () {
|
||||
const { data: { data, spaceBetween }, labelAxisTagPos, axisOriginPos, horizon } = this
|
||||
|
||||
const columnData = this.columnData = data.filter(({ type }) =>
|
||||
!(type === 'polyline' || type === 'smoothline'))
|
||||
|
||||
const columnItemSeriesNum = this.columnItemSeriesNum = columnData.length
|
||||
|
||||
const columnItemAllWidth = this.columnItemAllWidth = (horizon
|
||||
? axisOriginPos[1] - labelAxisTagPos[0][1]
|
||||
: labelAxisTagPos[0][0] - axisOriginPos[0]) * 2
|
||||
|
||||
const columnItemWidth = this.columnItemWidth = columnItemAllWidth / (columnItemSeriesNum + 1)
|
||||
|
||||
const spaceGap = columnItemWidth / (columnItemSeriesNum + 1)
|
||||
|
||||
let columnBGWidth = columnItemWidth * columnItemSeriesNum
|
||||
|
||||
spaceBetween && (columnBGWidth += spaceGap * (columnItemSeriesNum - 1))
|
||||
|
||||
this.columnBGWidth = columnBGWidth
|
||||
},
|
||||
calcColumnItemOffset () {
|
||||
const { columnItemSeriesNum, columnItemAllWidth, columnItemWidth } = this
|
||||
|
||||
const { data: { spaceBetween, data } } = this
|
||||
|
||||
const halfColumnWidth = columnItemWidth / 2
|
||||
|
||||
const halfColumnItemAllWidth = columnItemAllWidth / 2
|
||||
|
||||
let columnItemOffset = new Array(columnItemSeriesNum).fill(0)
|
||||
|
||||
if (spaceBetween) {
|
||||
const spaceGap = columnItemWidth / (columnItemSeriesNum + 1)
|
||||
|
||||
columnItemOffset = columnItemOffset.map((t, i) =>
|
||||
spaceGap * (i + 1) + columnItemWidth * i + halfColumnWidth - halfColumnItemAllWidth)
|
||||
}
|
||||
|
||||
if (!spaceBetween) {
|
||||
columnItemOffset = columnItemOffset.map((t, i) =>
|
||||
columnItemWidth * (i + 1) - halfColumnItemAllWidth)
|
||||
}
|
||||
|
||||
this.columnItemOffset = data.map(({ type }) =>
|
||||
(type === 'polyline' || type === 'smoothline')
|
||||
? 0
|
||||
: columnItemOffset.shift())
|
||||
},
|
||||
calcValuePointPos () {
|
||||
const { getAxisPointsPos, valueAxisMaxMin, agValueAxisMaxMin } = this
|
||||
|
||||
const { labelAxisTagPos, deepClone, filterNull, multipleSum } = this
|
||||
|
||||
const { data: { data }, axisOriginPos, axisWH, horizon } = this
|
||||
|
||||
const dealAfterData = deepClone(data).map(({ data, againstAxis }) => {
|
||||
if (!(data[0] instanceof Array)) return { data, againstAxis }
|
||||
|
||||
const td = data.map(series => series.map((v, i) => {
|
||||
if (!v && v !== 0) return false
|
||||
|
||||
return multipleSum(...filterNull(series.slice(0, i + 1)))
|
||||
}))
|
||||
|
||||
return { data: td, againstAxis }
|
||||
})
|
||||
|
||||
this.valuePointPos = dealAfterData.map(({ data, againstAxis }) =>
|
||||
getAxisPointsPos(
|
||||
againstAxis ? agValueAxisMaxMin : valueAxisMaxMin,
|
||||
data,
|
||||
axisOriginPos,
|
||||
axisWH,
|
||||
labelAxisTagPos,
|
||||
horizon
|
||||
))
|
||||
},
|
||||
drawColumnBG () {
|
||||
const { ctx, data: { showColumnBG, columnBGColor, roundColumn } } = this
|
||||
|
||||
if (!showColumnBG) return
|
||||
|
||||
const { columnBGWidth, defaultColumnBGColor, horizon, axisWH: [w, h], labelAxisTagPos } = this
|
||||
|
||||
const trueColumnColor = columnBGColor || defaultColumnBGColor
|
||||
|
||||
ctx.lineWidth = columnBGWidth
|
||||
ctx.strokeStyle = trueColumnColor
|
||||
ctx.setLineDash([10, 0])
|
||||
|
||||
const { getRoundColumnPoint, labelAxisTag } = this
|
||||
|
||||
ctx.lineCap = roundColumn ? 'round' : 'butt'
|
||||
|
||||
labelAxisTagPos.forEach(([x, y], i) => {
|
||||
if (!labelAxisTag[i] && labelAxisTag[i] !== 0) return
|
||||
|
||||
const topPoint = horizon ? [x + w, y] : [x, y - h]
|
||||
let columnBGPoints = [[x, y], topPoint]
|
||||
|
||||
roundColumn && (columnBGPoints = getRoundColumnPoint(columnBGPoints, columnBGWidth))
|
||||
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.moveTo(...columnBGPoints[0])
|
||||
ctx.lineTo(...columnBGPoints[1])
|
||||
|
||||
ctx.stroke()
|
||||
})
|
||||
},
|
||||
drawFigure () {
|
||||
const { data: { data }, valuePointPos } = this
|
||||
|
||||
const { drawColumn, drawEchelon, drawline } = this
|
||||
|
||||
data.forEach((series, i) => {
|
||||
switch (series.type) {
|
||||
case 'leftEchelon':
|
||||
case 'rightEchelon': drawEchelon(series, valuePointPos[i], i)
|
||||
break
|
||||
|
||||
case 'polyline':
|
||||
case 'smoothline': drawline(series, valuePointPos[i], i)
|
||||
break
|
||||
|
||||
default: drawColumn(series, valuePointPos[i], i)
|
||||
break
|
||||
}
|
||||
})
|
||||
},
|
||||
getGradientColor (value, colors) {
|
||||
const { data: { localGradient }, axisAnglePos, horizon } = this
|
||||
|
||||
const { ctx, canvas: { getLinearGradientColor } } = this
|
||||
|
||||
if (localGradient) {
|
||||
return getLinearGradientColor(ctx,
|
||||
...(horizon
|
||||
? [value, [axisAnglePos.leftTop[0], value[1]]]
|
||||
: [value, [value[0], axisAnglePos.leftBottom[1]]]),
|
||||
colors)
|
||||
} else {
|
||||
return getLinearGradientColor(ctx,
|
||||
...(horizon
|
||||
? [axisAnglePos.leftTop, axisAnglePos.rightTop]
|
||||
: [axisAnglePos.leftTop, axisAnglePos.leftBottom]),
|
||||
colors)
|
||||
}
|
||||
},
|
||||
drawColumn ({ fillColor }, points, i) {
|
||||
const { ctx, columnItemWidth, drawColors } = this
|
||||
|
||||
ctx.setLineDash([10, 0])
|
||||
ctx.lineWidth = columnItemWidth
|
||||
|
||||
const color = fillColor || drawColors[i]
|
||||
const colorNum = color.length
|
||||
const drawColorNum = drawColors.length
|
||||
|
||||
const { columnItemOffset, labelAxisTagPos, getOffsetPoint } = this
|
||||
|
||||
const currentOffset = columnItemOffset[i]
|
||||
const offsetTagPos = labelAxisTagPos.map(p => getOffsetPoint(p, currentOffset))
|
||||
|
||||
const { getGradientColor, getRoundColumnPoint, data: { roundColumn } } = this
|
||||
|
||||
ctx.lineCap = roundColumn ? 'round' : 'butt'
|
||||
|
||||
const seriesColumn = points[0][0] instanceof Array
|
||||
|
||||
seriesColumn && points.forEach((series, j) => {
|
||||
let lastEnd = offsetTagPos[j]
|
||||
|
||||
series.forEach((item, k) => {
|
||||
if (!item && item !== 0) return
|
||||
|
||||
const currentPoint = getOffsetPoint(item, currentOffset)
|
||||
|
||||
let columnPoint = [lastEnd, currentPoint]
|
||||
|
||||
roundColumn && (columnPoint = getRoundColumnPoint(columnPoint))
|
||||
|
||||
if (typeof color === 'string') {
|
||||
ctx.strokeStyle = drawColors[(i + k) % drawColorNum]
|
||||
} else {
|
||||
ctx.strokeStyle = color[k % colorNum]
|
||||
}
|
||||
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(...columnPoint[0])
|
||||
ctx.lineTo(...columnPoint[1])
|
||||
ctx.stroke()
|
||||
|
||||
lastEnd = currentPoint
|
||||
})
|
||||
})
|
||||
|
||||
!seriesColumn && points.forEach((point, i) => {
|
||||
if (!point && point !== 0) return
|
||||
|
||||
let columnPoint = [offsetTagPos[i], getOffsetPoint(point, currentOffset)]
|
||||
|
||||
roundColumn && (columnPoint = getRoundColumnPoint(columnPoint))
|
||||
|
||||
ctx.beginPath()
|
||||
ctx.strokeStyle = getGradientColor(point, color)
|
||||
ctx.moveTo(...columnPoint[0])
|
||||
ctx.lineTo(...columnPoint[1])
|
||||
ctx.stroke()
|
||||
})
|
||||
},
|
||||
getOffsetPoint ([x, y], offset) {
|
||||
const { horizon } = this
|
||||
|
||||
return horizon
|
||||
? [x, y + offset]
|
||||
: [x + offset, y]
|
||||
},
|
||||
getOffsetPoints (points, offset) {
|
||||
const { getOffsetPoint } = this
|
||||
|
||||
return points.map(point => point ? getOffsetPoint(point, offset) : false)
|
||||
},
|
||||
getRoundColumnPoint ([pa, pb], cw = false) {
|
||||
const { horizon, columnItemWidth: dciw } = this
|
||||
|
||||
const columnWidth = cw || dciw
|
||||
|
||||
const radius = columnWidth / 2
|
||||
|
||||
let [a, b, c, d] = [0, 0, 0, 0]
|
||||
|
||||
if (horizon) {
|
||||
a = pa[0] + radius
|
||||
b = pa[1]
|
||||
c = pb[0] - radius
|
||||
d = pb[1]
|
||||
} else {
|
||||
a = pa[0]
|
||||
b = pa[1] - radius
|
||||
c = pb[0]
|
||||
d = pb[1] + radius
|
||||
}
|
||||
|
||||
return horizon ? [
|
||||
[a > c ? c : a, b],
|
||||
[c, d]
|
||||
] : [
|
||||
[a, b],
|
||||
[c, b > d ? d : b]
|
||||
]
|
||||
},
|
||||
drawline ({ lineColor, fillColor, pointColor, lineType, lineDash, type }, points, i) {
|
||||
const { drawColors, ctx, axisOriginPos: [x, y], horizon } = this
|
||||
|
||||
const { color: { hexToRgb }, getGradientColor, getTopPoint } = this
|
||||
|
||||
const drawColorNum = drawColors.length
|
||||
const currentColor = drawColors[i % drawColorNum]
|
||||
|
||||
let currentLineColor = hexToRgb(currentColor, 0.6)
|
||||
let currentPointColor = currentColor
|
||||
|
||||
lineColor && (currentLineColor = lineColor)
|
||||
pointColor && (currentPointColor = pointColor)
|
||||
|
||||
let currentLineType = lineType || 'line'
|
||||
let currentLineDash = currentLineType === 'dashed' ? (lineDash || [5, 5]) : [10, 0]
|
||||
|
||||
ctx.strokeStyle = currentLineColor
|
||||
|
||||
const { canvas: { drawPolylinePath, drawPolyline, drawPoints } } = this
|
||||
const { canvas: { drawSmoothlinePath, drawSmoothline } } = this
|
||||
|
||||
const lineFun = type === 'polyline' ? [drawPolylinePath, drawPolyline] : [drawSmoothlinePath, drawSmoothline]
|
||||
|
||||
if (fillColor) {
|
||||
const lastPoint = points[points.length - 1]
|
||||
|
||||
ctx.fillStyle = getGradientColor(getTopPoint(points), fillColor)
|
||||
|
||||
lineFun[0](ctx, points, false, true, true)
|
||||
ctx.lineTo(...(horizon ? [x, lastPoint[1]] : [lastPoint[0], y]))
|
||||
ctx.lineTo(...(horizon ? [x, points[0][1]] : [points[0][0], y]))
|
||||
|
||||
ctx.closePath()
|
||||
ctx.fill()
|
||||
}
|
||||
|
||||
lineFun[1](ctx, points, 1, currentLineColor, false, currentLineDash, true, true)
|
||||
|
||||
drawPoints(ctx, points, 2, currentPointColor)
|
||||
},
|
||||
getTopPoint (points) {
|
||||
const { horizon } = this
|
||||
|
||||
let topIndex = 0
|
||||
|
||||
const xPos = points.map(([x]) => x)
|
||||
const yPos = points.map(([, y]) => y)
|
||||
|
||||
if (horizon) {
|
||||
const top = Math.max(...xPos)
|
||||
|
||||
topIndex = xPos.findIndex(v => v === top)
|
||||
}
|
||||
|
||||
if (!horizon) {
|
||||
const top = Math.min(...yPos)
|
||||
|
||||
topIndex = yPos.findIndex(v => v === top)
|
||||
}
|
||||
|
||||
return points[topIndex]
|
||||
},
|
||||
drawEchelon ({ fillColor, type }, points, i) {
|
||||
const { data: { roundColumn } } = this
|
||||
|
||||
const seriesColumn = points[0][0] instanceof Array
|
||||
|
||||
if (seriesColumn || roundColumn) return
|
||||
|
||||
const { ctx, columnItemOffset, labelAxisTagPos, getOffsetPoint } = this
|
||||
|
||||
const currentOffset = columnItemOffset[i]
|
||||
const offsetTagPos = labelAxisTagPos.map(p => getOffsetPoint(p, currentOffset))
|
||||
|
||||
const { drawColors, getGradientColor, getEchelonPoints } = this
|
||||
|
||||
const drawColorsNum = drawColors.length
|
||||
|
||||
const color = fillColor || drawColors[i % drawColorsNum]
|
||||
|
||||
const { canvas: { drawPolylinePath } } = this
|
||||
|
||||
points.forEach((point, i) => {
|
||||
const topPoint = getOffsetPoint(point, currentOffset)
|
||||
const bottomPoint = offsetTagPos[i]
|
||||
|
||||
const echelonPoints = getEchelonPoints(topPoint, bottomPoint, type)
|
||||
|
||||
drawPolylinePath(ctx, echelonPoints, true, true)
|
||||
|
||||
ctx.fillStyle = getGradientColor(point, color)
|
||||
|
||||
ctx.fill()
|
||||
})
|
||||
},
|
||||
getEchelonPoints ([tx, ty], [bx, by], type) {
|
||||
const { columnItemWidth, echelonOffset, horizon } = this
|
||||
|
||||
const halfWidth = columnItemWidth / 2
|
||||
|
||||
const echelonPoint = []
|
||||
|
||||
if (horizon) {
|
||||
let enhance = tx - bx < echelonOffset
|
||||
|
||||
if (type === 'leftEchelon') {
|
||||
echelonPoint[0] = [tx, ty + halfWidth]
|
||||
echelonPoint[1] = [bx, ty + halfWidth]
|
||||
echelonPoint[2] = [bx + echelonOffset, by - halfWidth]
|
||||
echelonPoint[3] = [tx, ty - halfWidth]
|
||||
}
|
||||
|
||||
if (type === 'rightEchelon') {
|
||||
echelonPoint[0] = [tx, ty - halfWidth]
|
||||
echelonPoint[1] = [bx, ty - halfWidth]
|
||||
echelonPoint[2] = [bx + echelonOffset, by + halfWidth]
|
||||
echelonPoint[3] = [tx, ty + halfWidth]
|
||||
}
|
||||
|
||||
if (enhance) echelonPoint.splice(2, 1)
|
||||
}
|
||||
|
||||
if (!horizon) {
|
||||
let enhance = by - ty < echelonOffset
|
||||
|
||||
if (type === 'leftEchelon') {
|
||||
echelonPoint[0] = [tx + halfWidth, ty]
|
||||
echelonPoint[1] = [tx + halfWidth, by]
|
||||
echelonPoint[2] = [tx - halfWidth, by - echelonOffset]
|
||||
echelonPoint[3] = [tx - halfWidth, ty]
|
||||
}
|
||||
|
||||
if (type === 'rightEchelon') {
|
||||
echelonPoint[0] = [tx - halfWidth, ty]
|
||||
echelonPoint[1] = [tx - halfWidth, by]
|
||||
echelonPoint[2] = [tx + halfWidth, by - echelonOffset]
|
||||
echelonPoint[3] = [tx + halfWidth, ty]
|
||||
}
|
||||
|
||||
if (enhance) echelonPoint.splice(2, 1)
|
||||
}
|
||||
|
||||
return echelonPoint
|
||||
},
|
||||
drawValueText () {
|
||||
const { data: { showValueText }, horizon } = this
|
||||
|
||||
if (!showValueText) return
|
||||
|
||||
const { data: { valueTextFontSize, valueTextOffset, data } } = this
|
||||
|
||||
const { ctx, defaultValueFontSize } = this
|
||||
|
||||
const offset = horizon ? [5, 0] : [0, -5]
|
||||
|
||||
const trueOffset = valueTextOffset || offset
|
||||
|
||||
ctx.font = `${valueTextFontSize || defaultValueFontSize}px Arial`
|
||||
|
||||
ctx.textAlign = horizon ? 'left' : 'center'
|
||||
ctx.textBaseline = horizon ? 'middle' : 'bottom'
|
||||
|
||||
const { drawSeriesTextValue } = this
|
||||
|
||||
data.forEach((series, i) => drawSeriesTextValue(series, i, trueOffset))
|
||||
},
|
||||
drawSeriesTextValue ({ data, valueTextColor, fillColor, lineColor }, i, trueOffset) {
|
||||
const { ctx, valuePointPos, columnItemOffset, drawTexts, getOffsetPoints, drawColors } = this
|
||||
|
||||
const { data: { valueTextColor: outerValueTC }, defaultValueColor } = this
|
||||
|
||||
const drawColorsNum = drawColors.length
|
||||
|
||||
let currentColor = valueTextColor
|
||||
currentColor === 'inherit' && (currentColor = fillColor || lineColor || drawColors[i % drawColorsNum])
|
||||
const mulColor = currentColor instanceof Array
|
||||
const colorNum = mulColor ? currentColor.length : 0
|
||||
|
||||
const currentPos = valuePointPos[i]
|
||||
const currentOffset = columnItemOffset[i]
|
||||
|
||||
const mulSeries = data[0] instanceof Array
|
||||
|
||||
if (mulSeries) {
|
||||
data.forEach((item, j) => {
|
||||
const pointPos = getOffsetPoints(currentPos[j], currentOffset)
|
||||
|
||||
item.forEach((v, l) => {
|
||||
!currentColor && (ctx.fillStyle = defaultValueColor)
|
||||
currentColor && (ctx.fillStyle = mulColor ? currentColor[l % colorNum] : currentColor)
|
||||
drawTexts(ctx, [item[l]], [pointPos[l]], trueOffset)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (!mulSeries) {
|
||||
mulColor && (currentColor = currentColor[0])
|
||||
|
||||
ctx.fillStyle = currentColor || outerValueTC || defaultValueColor
|
||||
drawTexts(ctx, data, getOffsetPoints(currentPos, currentOffset), trueOffset)
|
||||
}
|
||||
},
|
||||
drawTexts (ctx, values, points, [x, y] = [0, 0]) {
|
||||
values.forEach((v, i) => {
|
||||
if (!v && v !== 0) return
|
||||
|
||||
ctx.fillText(v, points[i][0] + x, points[i][1] + y)
|
||||
})
|
||||
},
|
||||
drawCenterOriginTypeColumnChart () {}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.column-chart {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.canvas-container {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,178 +0,0 @@
|
||||
<template>
|
||||
<div class="concentric-arc-chart">
|
||||
<loading v-if="!data" />
|
||||
|
||||
<canvas :ref="ref" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ConcentricArcChart',
|
||||
props: ['data'],
|
||||
data () {
|
||||
return {
|
||||
ref: `concentric-arc-chart-${(new Date()).getTime()}`,
|
||||
canvasDom: '',
|
||||
canvasWH: [0, 0],
|
||||
ctx: '',
|
||||
|
||||
arcOriginPos: [],
|
||||
|
||||
defaultArcRadiusArea: [0.2, 0.8],
|
||||
defaultArcGap: 3,
|
||||
defaultArcColor: ['#00c0ff', '#3de7c9'],
|
||||
|
||||
arcRadius: [],
|
||||
arcRadian: [],
|
||||
arcLineWidth: 0,
|
||||
arcColor: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
data (d) {
|
||||
const { draw } = this
|
||||
|
||||
d && draw()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const { $nextTick, initCanvas, calcArcConfig, data, draw } = this
|
||||
|
||||
$nextTick(e => {
|
||||
initCanvas()
|
||||
|
||||
calcArcConfig()
|
||||
|
||||
data && draw()
|
||||
})
|
||||
},
|
||||
initCanvas () {
|
||||
const { $refs, ref, labelRef, canvasWH } = this
|
||||
|
||||
const canvas = this.canvasDom = $refs[ref]
|
||||
|
||||
this.labelDom = $refs[labelRef]
|
||||
|
||||
canvasWH[0] = canvas.clientWidth
|
||||
canvasWH[1] = canvas.clientHeight
|
||||
|
||||
canvas.setAttribute('width', canvasWH[0])
|
||||
canvas.setAttribute('height', canvasWH[1])
|
||||
|
||||
this.ctx = canvas.getContext('2d')
|
||||
},
|
||||
calcArcConfig () {
|
||||
const { canvasWH, arcOriginPos } = this
|
||||
|
||||
arcOriginPos[0] = canvasWH[0] / 2
|
||||
arcOriginPos[1] = canvasWH[1] / 2
|
||||
},
|
||||
draw () {
|
||||
const { ctx, canvasWH, calcArcRadius, calcArcRadian, calcArcColor, drawArc, drawTitle } = this
|
||||
|
||||
ctx.clearRect(0, 0, ...canvasWH)
|
||||
|
||||
calcArcRadius()
|
||||
|
||||
calcArcRadian()
|
||||
|
||||
calcArcColor()
|
||||
|
||||
drawArc()
|
||||
|
||||
drawTitle()
|
||||
},
|
||||
calcArcRadius () {
|
||||
const { data: { data, arcArea, arcGap }, arcOriginPos, defaultArcRadiusArea, defaultArcGap } = this
|
||||
|
||||
const arcNum = data.length
|
||||
|
||||
const fullRadius = (arcOriginPos[0] > arcOriginPos[1] ? arcOriginPos[1] : arcOriginPos[0])
|
||||
|
||||
const currentArcArea = arcArea || defaultArcRadiusArea
|
||||
|
||||
const maxRadius = fullRadius * Math.max(...currentArcArea)
|
||||
const minRadius = fullRadius * Math.min(...currentArcArea)
|
||||
|
||||
const currentArcGap = arcGap || defaultArcGap
|
||||
|
||||
const arcLineWidth = this.arcLineWidth = (maxRadius - minRadius - currentArcGap * (arcNum - 1)) / arcNum
|
||||
|
||||
const fullArcLineWidth = arcLineWidth + currentArcGap
|
||||
const halfArcLineWidth = arcLineWidth / 2
|
||||
|
||||
this.arcRadius = new Array(arcNum).fill(0).map((t, i) => maxRadius - halfArcLineWidth - fullArcLineWidth * i)
|
||||
},
|
||||
calcArcRadian () {
|
||||
const { data: { data } } = this
|
||||
|
||||
const fullRadian = Math.PI / 2 * 3
|
||||
|
||||
const offsetRadian = Math.PI * 0.5
|
||||
|
||||
this.arcRadian = new Array(data.length).fill(0).map((t, i) => data[i].value * fullRadian - offsetRadian)
|
||||
},
|
||||
calcArcColor () {
|
||||
const { ctx, arcLineWidth, defaultArcColor, canvas: { getLinearGradientColor } } = this
|
||||
|
||||
const { data: { color }, arcRadius: [ radius ], arcOriginPos: [x, y] } = this
|
||||
|
||||
const colors = color || defaultArcColor
|
||||
|
||||
this.arcColor = getLinearGradientColor(ctx,
|
||||
[x, y - radius - arcLineWidth],
|
||||
[x, y + radius + arcLineWidth], colors)
|
||||
},
|
||||
drawArc () {
|
||||
const { ctx, arcRadius, arcRadian, arcOriginPos, arcLineWidth, arcColor } = this
|
||||
|
||||
const offsetRadian = Math.PI / -2
|
||||
|
||||
ctx.lineWidth = arcLineWidth
|
||||
ctx.strokeStyle = arcColor
|
||||
|
||||
arcRadius.forEach((radius, i) => {
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.arc(...arcOriginPos, radius, offsetRadian, arcRadian[i])
|
||||
|
||||
ctx.stroke()
|
||||
})
|
||||
},
|
||||
drawTitle () {
|
||||
const { ctx, data: { data, fontSize }, arcRadius, arcOriginPos: [ x, y ], arcLineWidth } = this
|
||||
|
||||
const textEndX = x - 10
|
||||
|
||||
ctx.font = `${fontSize || arcLineWidth}px Arial`
|
||||
ctx.textAlign = 'right'
|
||||
ctx.textBaseline = 'middle'
|
||||
ctx.fillStyle = '#fff'
|
||||
|
||||
ctx.beginPath()
|
||||
|
||||
data.forEach(({ title }, i) => {
|
||||
ctx.fillText(title, textEndX, y - arcRadius[i])
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.concentric-arc-chart {
|
||||
position: relative;
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 48 KiB |
@ -1,20 +0,0 @@
|
||||
<template>
|
||||
<div class="decoration-1">
|
||||
<img src="./img/decoration.gif" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Decoration1'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.decoration-1 {
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,77 +0,0 @@
|
||||
<template>
|
||||
<div class="decoration-2" :ref="ref">
|
||||
<div :class="reverse ? 'reverse' : 'normal'" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Decoration2',
|
||||
data () {
|
||||
return {
|
||||
ref: `decoration-2-${(new Date()).getTime()}`,
|
||||
width: 0,
|
||||
height: 0
|
||||
}
|
||||
},
|
||||
props: ['reverse'],
|
||||
methods: {
|
||||
init () {
|
||||
const { $nextTick, $refs, ref } = this
|
||||
|
||||
$nextTick(e => {
|
||||
this.width = $refs[ref].clientWidth
|
||||
this.height = $refs[ref].clientHeight
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.decoration-2 {
|
||||
|
||||
.reverse, .normal {
|
||||
background-color: #3faacb;
|
||||
}
|
||||
|
||||
.normal {
|
||||
width: 0%;
|
||||
height: 1px;
|
||||
border-right: 1px solid #fff;
|
||||
animation: normal-amt 6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.reverse {
|
||||
width: 1px;
|
||||
height: 0%;
|
||||
border-bottom: 1px solid #fff;
|
||||
animation: reverse-amt 6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes reverse-amt {
|
||||
70% {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes normal-amt {
|
||||
70% {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 86 KiB |
@ -1,20 +0,0 @@
|
||||
<template>
|
||||
<div class="decoration-3">
|
||||
<img src="./img/decoration.gif" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Decoration3'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.decoration-3 {
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,107 +0,0 @@
|
||||
<template>
|
||||
<div :class="`decoration-4 ${reverse ? 'reverse' : 'normal'}`" :ref="ref">
|
||||
<svg :class="`svg-container ${reverse ? 'ani-width' : 'ani-height'}`">
|
||||
<template v-if="!reverse">
|
||||
<polyline class="lighter-line" :points="`3, 5 3, ${height - 5}`" />
|
||||
<polyline class="bolder-line" :points="`3, 5 3, ${height - 5}`" />
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<polyline class="lighter-line" :points="`5, 3 ${width - 5},3`" />
|
||||
<polyline class="bolder-line" :points="`5, 3 ${width - 5},3`" />
|
||||
</template>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Decoration4',
|
||||
data () {
|
||||
return {
|
||||
ref: `decoration-4-${(new Date()).getTime()}`,
|
||||
width: 0,
|
||||
height: 0
|
||||
}
|
||||
},
|
||||
props: ['reverse'],
|
||||
methods: {
|
||||
init () {
|
||||
const { $nextTick, $refs, ref } = this
|
||||
|
||||
$nextTick(e => {
|
||||
this.width = $refs[ref].clientWidth
|
||||
this.height = $refs[ref].clientHeight
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.decoration-4 {
|
||||
|
||||
&.normal {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&.reverse {
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.svg-container {
|
||||
|
||||
&.ani-height {
|
||||
width: 100%;
|
||||
height: 0%;
|
||||
animation: ani-height 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
&.ani-width {
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
animation: ani-width 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
polyline {
|
||||
fill: none;
|
||||
stroke: fade(gray, 25);
|
||||
}
|
||||
}
|
||||
|
||||
.lighter-line {
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.bolder-line {
|
||||
stroke-width: 3px;
|
||||
stroke-dasharray: 20, 80;
|
||||
stroke-dashoffset: -30;
|
||||
}
|
||||
|
||||
@keyframes ani-height {
|
||||
70% {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ani-width {
|
||||
70% {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 20 KiB |
@ -1,22 +0,0 @@
|
||||
<template>
|
||||
<div class="decoration-5">
|
||||
<img src="./img/decoration.gif" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Decoration5'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.decoration-5 {
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
margin-top: -21%;
|
||||
margin-bottom: -25%;
|
||||
}
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 242 KiB |
@ -1,20 +0,0 @@
|
||||
<template>
|
||||
<div class="decoration-6">
|
||||
<img src="./img/decoration.gif" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Decoration6'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.decoration-6 {
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 496 B |
@ -1,26 +0,0 @@
|
||||
<template>
|
||||
<div class="decoration-7">
|
||||
<img src="./img/decoration.png" />
|
||||
<slot></slot>
|
||||
<img class="reverse" src="./img/decoration.png" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Decoration7'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.decoration-7 {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.reverse {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<div class="for-slot">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ForSlot'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.for-slot {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
</style>
|
@ -1,71 +0,0 @@
|
||||
import borderBox1 from './borderBox1/index'
|
||||
import borderBox2 from './borderBox2/index'
|
||||
import borderBox3 from './borderBox3/index'
|
||||
import borderBox4 from './borderBox4/index'
|
||||
import borderBox5 from './borderBox5/index'
|
||||
import borderBox6 from './borderBox6/index'
|
||||
import borderBox7 from './borderBox7/index'
|
||||
|
||||
import decoration1 from './decoration1/index'
|
||||
import decoration2 from './decoration2/index'
|
||||
import decoration3 from './decoration3/index'
|
||||
import decoration4 from './decoration4/index'
|
||||
import decoration5 from './decoration5/index'
|
||||
import decoration6 from './decoration6/index'
|
||||
import decoration7 from './decoration7/index'
|
||||
import loading from './loading/index.vue'
|
||||
|
||||
import capsuleChart from './capsuleChart/index.vue'
|
||||
import ringChart from './ringChart/index.vue'
|
||||
import polylineChart from './polylineChart/index.vue'
|
||||
import concentricArcChart from './concentricArcChart/index.vue'
|
||||
import arcRingChart from './arcRingChart/index.vue'
|
||||
import radarChart from './radarChart/index.vue'
|
||||
import columnChart from './columnChart/index.vue'
|
||||
import pointChart from './pointChart/index.vue'
|
||||
|
||||
import numberShow from './numberShow/index.vue'
|
||||
import percentPond from './percentPond/index.vue'
|
||||
import percentArc from './percentArc/index.vue'
|
||||
import waterLevelPond from './waterLevelPond/index.vue'
|
||||
import scrollBoard from './scrollBoard/index.vue'
|
||||
|
||||
import labelLine from './labelLine'
|
||||
import forSlot from './forSlot'
|
||||
|
||||
export default function (Vue) {
|
||||
Vue.component('borderBox1', borderBox1)
|
||||
Vue.component('borderBox2', borderBox2)
|
||||
Vue.component('borderBox3', borderBox3)
|
||||
Vue.component('borderBox4', borderBox4)
|
||||
Vue.component('borderBox5', borderBox5)
|
||||
Vue.component('borderBox6', borderBox6)
|
||||
Vue.component('borderBox7', borderBox7)
|
||||
|
||||
Vue.component('decoration1', decoration1)
|
||||
Vue.component('decoration2', decoration2)
|
||||
Vue.component('decoration3', decoration3)
|
||||
Vue.component('decoration4', decoration4)
|
||||
Vue.component('decoration5', decoration5)
|
||||
Vue.component('decoration6', decoration6)
|
||||
Vue.component('decoration7', decoration7)
|
||||
Vue.component('loading', loading)
|
||||
|
||||
Vue.component('capsuleChart', capsuleChart)
|
||||
Vue.component('polylineChart', polylineChart)
|
||||
Vue.component('ringChart', ringChart)
|
||||
Vue.component('concentricArcChart', concentricArcChart)
|
||||
Vue.component('arcRingChart', arcRingChart)
|
||||
Vue.component('radarChart', radarChart)
|
||||
Vue.component('columnChart', columnChart)
|
||||
Vue.component('pointChart', pointChart)
|
||||
|
||||
Vue.component('numberShow', numberShow)
|
||||
Vue.component('percentPond', percentPond)
|
||||
Vue.component('percentArc', percentArc)
|
||||
Vue.component('waterLevelPond', waterLevelPond)
|
||||
Vue.component('scrollBoard', scrollBoard)
|
||||
|
||||
Vue.component('labelLine', labelLine)
|
||||
Vue.component('forSlot', forSlot)
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
<template>
|
||||
<div class="label-line">
|
||||
<div class="label-item"
|
||||
v-for="(labelItem, i) in labelData"
|
||||
:key="labelItem">
|
||||
<div :class="type" :style="`background-color: ${labelColor[i % labelColorNum]};`"></div>
|
||||
<div>{{ labelItem }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'LabelLine',
|
||||
props: ['label', 'colors'],
|
||||
data () {
|
||||
return {
|
||||
labelData: [],
|
||||
labelColor: [],
|
||||
labelColorNum: 0,
|
||||
type: 'rect'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
label () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
},
|
||||
colors () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const { label, colors } = this
|
||||
|
||||
if (!label) return
|
||||
|
||||
const { data, color, type } = label
|
||||
|
||||
if (!data) return
|
||||
|
||||
this.labelData = data
|
||||
|
||||
let trueColor = color || colors
|
||||
|
||||
typeof trueColor === 'string' && (trueColor = [trueColor])
|
||||
|
||||
this.labelColor = trueColor
|
||||
|
||||
this.labelColorNum = trueColor.length
|
||||
|
||||
this.type = type || 'rect'
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.label-line {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
font-size: 10px;
|
||||
color: #fff;
|
||||
|
||||
.label-item {
|
||||
height: 20px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin: 0px 5px 5px 5px;
|
||||
}
|
||||
|
||||
.rect {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.rectangle {
|
||||
width: 30px;
|
||||
height: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 6.1 KiB |
@ -1,39 +0,0 @@
|
||||
<template>
|
||||
<div class="loading">
|
||||
<img class="loading-img" src="./img/loading.png">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Loading'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.loading {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.loading-img {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-left: -15px;
|
||||
margin-top: -15px;
|
||||
transform: rotate(0deg);
|
||||
animation: round 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes round {
|
||||
to {
|
||||
transform: rotate(360deg)
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,33 +0,0 @@
|
||||
<template>
|
||||
<div class="number-show">
|
||||
<div class="number-itme" v-for="(n, i) in number.toString()" :key="`${n}-${i}`">
|
||||
{{ n }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'NumberShow',
|
||||
props: ['number']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.number-show {
|
||||
display: inline-block;
|
||||
|
||||
.number-itme {
|
||||
display: inline-block;
|
||||
height: 70px;
|
||||
padding: 0 20px;
|
||||
line-height: 70px;
|
||||
text-align: center;
|
||||
background-color: rgba(4, 49, 128, 0.6);
|
||||
margin-right: 20px;
|
||||
color: rgb(8, 229, 255);
|
||||
font-weight: bold;
|
||||
font-size: 45px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,222 +0,0 @@
|
||||
<template>
|
||||
<div class="percent-arc">
|
||||
<loading v-if="!percent || percent === 0" />
|
||||
|
||||
<div class="canvas-container">
|
||||
<canvas :ref="ref" />
|
||||
</div>
|
||||
|
||||
<div class="for-slot">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import canvasMixin from '../../mixins/canvasMixin.js'
|
||||
|
||||
export default {
|
||||
name: 'PercentArc',
|
||||
props: ['percent', 'ringColor', 'arcColor', 'ringLineWidth', 'arcLineWidth', 'radius', 'arcType'],
|
||||
mixins: [canvasMixin],
|
||||
data () {
|
||||
return {
|
||||
ref: `percent-arc-${(new Date()).getTime()}`,
|
||||
|
||||
defaultRadius: 0.9,
|
||||
defaultRingLineWidth: 4,
|
||||
defaultArcLineWidth: 10,
|
||||
defaultArcType: 'butt',
|
||||
|
||||
defaultRingColor: '#00BAFF',
|
||||
defaultArcColor: ['#00BAFF', '#3DE7C9'],
|
||||
|
||||
trueArcType: '',
|
||||
trueRadius: 0,
|
||||
ringRadius: 0,
|
||||
arcRadius: 0,
|
||||
trueRingColor: '',
|
||||
trueArcColor: '',
|
||||
trueRingLineWidth: 0,
|
||||
trueArcLineWidth: 0
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
percent () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
},
|
||||
ringColor () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
},
|
||||
arcColor () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
},
|
||||
ringLineWidth () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
},
|
||||
arcLineWidth () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
},
|
||||
radius () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
},
|
||||
arcType () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async init () {
|
||||
const { initCanvas, draw } = this
|
||||
|
||||
await initCanvas()
|
||||
|
||||
draw()
|
||||
},
|
||||
draw () {
|
||||
const { percent } = this
|
||||
|
||||
if (!percent && percent !== 0) return
|
||||
|
||||
const { clearCanvas } = this
|
||||
|
||||
clearCanvas()
|
||||
|
||||
const { calcLineWidth, calcRaidus, calcColors } = this
|
||||
|
||||
calcLineWidth()
|
||||
|
||||
calcRaidus()
|
||||
|
||||
calcColors()
|
||||
|
||||
const { calcArcType, drawRing, drawArc } = this
|
||||
|
||||
calcArcType()
|
||||
|
||||
drawRing()
|
||||
|
||||
drawArc()
|
||||
},
|
||||
calcLineWidth () {
|
||||
const { defaultRingLineWidth, defaultArcLineWidth, ringLineWidth, arcLineWidth } = this
|
||||
|
||||
this.trueRingLineWidth = ringLineWidth || defaultRingLineWidth
|
||||
|
||||
this.trueArcLineWidth = arcLineWidth || defaultArcLineWidth
|
||||
},
|
||||
calcRaidus () {
|
||||
const { radius, defaultRadius, canvasWH } = this
|
||||
|
||||
const trueRadius = this.trueRadius = radius || defaultRadius
|
||||
|
||||
const ringRadius = this.ringRadius = Math.min(...canvasWH) * trueRadius / 2
|
||||
|
||||
const { trueRingLineWidth, trueArcLineWidth } = this
|
||||
|
||||
const halfRingLineWidth = trueRingLineWidth / 2
|
||||
|
||||
const halfArcLineWidth = trueArcLineWidth / 2
|
||||
|
||||
this.arcRadius = ringRadius - halfRingLineWidth - halfArcLineWidth
|
||||
},
|
||||
calcColors () {
|
||||
const { ringColor, defaultRingColor } = this
|
||||
|
||||
this.trueRingColor = ringColor || defaultRingColor
|
||||
|
||||
const { arcColor, defaultArcColor } = this
|
||||
|
||||
this.trueArcColor = arcColor || defaultArcColor
|
||||
},
|
||||
calcArcType () {
|
||||
const { arcType, defaultArcType } = this
|
||||
|
||||
this.trueArcType = arcType || defaultArcType
|
||||
},
|
||||
drawRing () {
|
||||
const { ringRadius, ctx, trueRingLineWidth, centerPos, trueRingColor } = this
|
||||
|
||||
ctx.lineWidth = trueRingLineWidth
|
||||
|
||||
ctx.strokeStyle = trueRingColor
|
||||
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.arc(...centerPos, ringRadius, 0, Math.PI * 2)
|
||||
|
||||
ctx.stroke()
|
||||
},
|
||||
drawArc () {
|
||||
const { ctx, centerPos, percent, trueArcType, canvasWH } = this
|
||||
|
||||
const { trueArcLineWidth, arcRadius, trueArcColor } = this
|
||||
|
||||
const { canvas: { getLinearGradientColor } } = this
|
||||
|
||||
const fullArc = Math.PI * 2
|
||||
|
||||
const offsetArc = Math.PI / 2
|
||||
|
||||
const arcBegin = offsetArc * -1
|
||||
|
||||
const arcEnd = fullArc * percent / 100 - offsetArc
|
||||
|
||||
ctx.lineCap = trueArcType
|
||||
|
||||
ctx.lineWidth = trueArcLineWidth
|
||||
|
||||
ctx.strokeStyle = getLinearGradientColor(ctx, [0, 0], [0, canvasWH[1]], trueArcColor)
|
||||
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.arc(...centerPos, arcRadius, arcBegin, arcEnd)
|
||||
|
||||
ctx.stroke()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.percent-arc {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
.canvas-container {
|
||||
flex: 1;
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.for-slot {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,139 +0,0 @@
|
||||
<template>
|
||||
<div class="percent-pond">
|
||||
<div class="percent-text">
|
||||
<span :style="`margin-left: ${percent * (width - 2) / 100 + 6}px`">{{ percent || 0 }}%</span>
|
||||
</div>
|
||||
|
||||
<div class="percent-container">
|
||||
<div class="p-decoration-box" />
|
||||
<div class="p-svg-container" :ref="ref">
|
||||
<svg :width="width" :height="height">
|
||||
<defs>
|
||||
<linearGradient id="linear">
|
||||
<stop v-for="lc in linearGradient" :key="lc[0]"
|
||||
:offset="lc[0]"
|
||||
:stop-color="lc[1]" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<polyline :stroke-width="height - 1"
|
||||
stroke="url(#linear)"
|
||||
:points="`1, ${height * 0.5} ${percent * (width - 2) / 100}, ${height * 0.5 + 0.0001}`" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="p-decoration-box" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PercentPond',
|
||||
props: ['percent', 'colors'],
|
||||
data () {
|
||||
return {
|
||||
ref: `percent-pond-${(new Date()).getTime()}`,
|
||||
width: 0,
|
||||
height: 0,
|
||||
|
||||
defaultColor: ['#00BAFF', '#3DE7C9'],
|
||||
|
||||
linearGradient: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
colors () {
|
||||
const { calcLinearColor } = this
|
||||
|
||||
calcLinearColor()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const { $nextTick, $refs, ref, calcLinearColor } = this
|
||||
|
||||
$nextTick(e => {
|
||||
this.width = $refs[ref].clientWidth
|
||||
this.height = $refs[ref].clientHeight
|
||||
})
|
||||
|
||||
calcLinearColor()
|
||||
},
|
||||
calcLinearColor () {
|
||||
const { colors, defaultColor } = this
|
||||
|
||||
let trueColor = colors || defaultColor
|
||||
|
||||
typeof trueColor === 'string' && (trueColor = [trueColor, trueColor])
|
||||
|
||||
const colorNum = trueColor.length
|
||||
|
||||
const colorOffsetGap = 100 / (colorNum - 1)
|
||||
|
||||
this.linearGradient = trueColor.map((c, i) => [colorOffsetGap * i, c])
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.percent-pond {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.percent-text {
|
||||
height: 30px;
|
||||
font-size: 15px;
|
||||
flex-shrink: 0;
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
box-shadow: 0 0 3px gray;
|
||||
padding: 0px 5px;
|
||||
display: inline-block;
|
||||
transform: translateX(-50%);
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
content: '';
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border-width: 8px;
|
||||
border-style: solid;
|
||||
border-color: fade(gray, 50) transparent transparent transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.percent-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.p-decoration-box {
|
||||
width: 3px;
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 0 3px gray;
|
||||
}
|
||||
|
||||
.p-svg-container {
|
||||
flex: 1;
|
||||
margin: 0px 3px;
|
||||
box-shadow: 0 0 3px gray;
|
||||
|
||||
polyline {
|
||||
fill: none;
|
||||
stroke-dasharray: 5, 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,155 +0,0 @@
|
||||
<template>
|
||||
<div class="point-chart">
|
||||
<loading v-if="!data" />
|
||||
|
||||
<div class="canvas-container">
|
||||
<canvas :ref="ref" />
|
||||
</div>
|
||||
|
||||
<label-line :label="data.labelLine" :colors="drawColors" />
|
||||
|
||||
<for-slot><slot></slot></for-slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import canvasMixin from '../../mixins/canvasMixin.js'
|
||||
|
||||
import colorsMixin from '../../mixins/colorsMixin.js'
|
||||
|
||||
import axisMixin from '../../mixins/axisMixin.js'
|
||||
|
||||
export default {
|
||||
name: 'PointChart',
|
||||
mixins: [canvasMixin, colorsMixin, axisMixin],
|
||||
props: ['data', 'colors'],
|
||||
data () {
|
||||
return {
|
||||
ref: `point-chart-${(new Date()).getTime()}`,
|
||||
|
||||
// axis base config
|
||||
boundaryGap: true,
|
||||
horizon: false,
|
||||
mulValueAdd: false,
|
||||
|
||||
defaultPointRadius: 2,
|
||||
|
||||
valuePointPos: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async init () {
|
||||
const { initCanvas, initColors, data, draw } = this
|
||||
|
||||
await initCanvas()
|
||||
|
||||
initColors()
|
||||
|
||||
data && draw()
|
||||
},
|
||||
draw () {
|
||||
const { clearCanvas } = this
|
||||
|
||||
clearCanvas()
|
||||
|
||||
const { initAxis, drawAxis, calcValuePointPos } = this
|
||||
|
||||
initAxis()
|
||||
|
||||
drawAxis()
|
||||
|
||||
calcValuePointPos()
|
||||
|
||||
const { drawPoints } = this
|
||||
|
||||
drawPoints()
|
||||
},
|
||||
calcValuePointPos () {
|
||||
const { data: { data }, valueAxisMaxMin, getAxisPointsPos } = this
|
||||
|
||||
const { axisOriginPos, axisWH, labelAxisTagPos } = this
|
||||
|
||||
this.valuePointPos = data.map(({ data: td }, i) =>
|
||||
getAxisPointsPos(
|
||||
valueAxisMaxMin,
|
||||
td,
|
||||
axisOriginPos,
|
||||
axisWH,
|
||||
labelAxisTagPos,
|
||||
false
|
||||
))
|
||||
},
|
||||
drawPoints () {
|
||||
const { data: { data }, drawSeriesPoint, ctx } = this
|
||||
|
||||
ctx.setLineDash([10, 0])
|
||||
|
||||
data.forEach((series, i) => drawSeriesPoint(series, i))
|
||||
},
|
||||
drawSeriesPoint ({ color: cr, edgeColor, fillColor, radius, opacity }, i) {
|
||||
const { drawColors, defaultPointRadius, valuePointPos, drawPoint } = this
|
||||
|
||||
const { color: { hexToRgb }, data: { radius: outerRadius } } = this
|
||||
|
||||
const drawColorsNum = drawColors.length
|
||||
|
||||
const baseColor = drawColors[i % drawColorsNum]
|
||||
|
||||
const trueEdgeColor = edgeColor || cr || baseColor
|
||||
|
||||
let trueFillColor = fillColor || cr || baseColor
|
||||
|
||||
opacity && (trueFillColor = hexToRgb(trueFillColor, opacity))
|
||||
|
||||
const trueRadius = radius || outerRadius || defaultPointRadius
|
||||
|
||||
valuePointPos[i].forEach(cp => {
|
||||
if (!cp && cp !== 0) return
|
||||
|
||||
const isSeries = cp[0] instanceof Array
|
||||
|
||||
isSeries && cp.forEach(p => (p || p === 0) && drawPoint(p, trueEdgeColor, trueFillColor, trueRadius))
|
||||
|
||||
!isSeries && drawPoint(cp, trueEdgeColor, trueFillColor, trueRadius)
|
||||
})
|
||||
},
|
||||
drawPoint (pos, edgeColor, fillColor, radius) {
|
||||
const { ctx } = this
|
||||
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.arc(...pos, radius, 0, Math.PI * 2)
|
||||
|
||||
ctx.closePath()
|
||||
|
||||
ctx.strokeStyle = edgeColor
|
||||
ctx.fillStyle = fillColor
|
||||
|
||||
ctx.fill()
|
||||
ctx.stroke()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.point-chart {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.canvas-container {
|
||||
flex: 1;
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,268 +0,0 @@
|
||||
<template>
|
||||
<div class="polyline-chart">
|
||||
<loading v-if="!data" />
|
||||
|
||||
<div class="canvas-container">
|
||||
<canvas :ref="ref" />
|
||||
</div>
|
||||
|
||||
<label-line :label="data.labelLine" :colors="drawColors" />
|
||||
|
||||
<for-slot><slot></slot></for-slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import colorsMixin from '../../mixins/colorsMixin.js'
|
||||
|
||||
import canvasMixin from '../../mixins/canvasMixin.js'
|
||||
|
||||
import axisMixin from '../../mixins/axisMixin.js'
|
||||
|
||||
export default {
|
||||
name: 'PolylineChart',
|
||||
mixins: [colorsMixin, canvasMixin, axisMixin],
|
||||
props: ['data', 'colors'],
|
||||
data () {
|
||||
return {
|
||||
ref: `polyline-chart-${(new Date()).getTime()}`,
|
||||
|
||||
// axis base config
|
||||
boundaryGap: false,
|
||||
mulValueAdd: false,
|
||||
horizon: false,
|
||||
|
||||
defaultLineDash: [10, 5],
|
||||
defaultPointRadius: 2,
|
||||
|
||||
defaultValueFontSize: 10,
|
||||
defaultValueColor: '#999',
|
||||
|
||||
valuePointPos: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
data (d) {
|
||||
const { draw } = this
|
||||
|
||||
d && draw()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async init () {
|
||||
const { initCanvas, initColors } = this
|
||||
|
||||
await initCanvas()
|
||||
|
||||
initColors()
|
||||
|
||||
const { data, draw } = this
|
||||
|
||||
data && draw()
|
||||
},
|
||||
draw () {
|
||||
const { clearCanvas } = this
|
||||
|
||||
clearCanvas()
|
||||
|
||||
const { initAxisConfig, initAxis, drawAxis } = this
|
||||
|
||||
initAxisConfig()
|
||||
|
||||
initAxis()
|
||||
|
||||
drawAxis()
|
||||
|
||||
const { calcValuePointPos, drawLines, drawFills } = this
|
||||
|
||||
calcValuePointPos()
|
||||
|
||||
drawLines()
|
||||
|
||||
drawFills()
|
||||
|
||||
const { drawPoints, drawValues } = this
|
||||
|
||||
drawPoints()
|
||||
|
||||
drawValues()
|
||||
},
|
||||
initAxisConfig () {
|
||||
const { data: { boundaryGap } } = this
|
||||
|
||||
this.boundaryGap = boundaryGap
|
||||
},
|
||||
calcValuePointPos () {
|
||||
const { valueAxisMaxMin, axisOriginPos, axisWH, labelAxisTagPos, horizon } = this
|
||||
|
||||
const { data: { data }, getAxisPointsPos } = this
|
||||
|
||||
this.valuePointPos = data.map(({ data, againstAxis }) =>
|
||||
getAxisPointsPos(
|
||||
valueAxisMaxMin,
|
||||
data,
|
||||
axisOriginPos,
|
||||
axisWH,
|
||||
labelAxisTagPos,
|
||||
horizon
|
||||
))
|
||||
},
|
||||
drawLines () {
|
||||
const { data: { data }, valuePointPos, drawLine } = this
|
||||
|
||||
data.forEach((line, i) => drawLine(line, valuePointPos[i], i))
|
||||
},
|
||||
drawLine ({ type, lineType, lineDash, lineColor }, points, i) {
|
||||
const { ctx, drawColors, defaultLineDash } = this
|
||||
|
||||
const { canvas: { drawPolyline, drawSmoothline } } = this
|
||||
|
||||
const { color: { hexToRgb } } = this
|
||||
|
||||
let drawLineFun = drawPolyline
|
||||
type === 'smoothline' && (drawLineFun = drawSmoothline)
|
||||
|
||||
let color = hexToRgb(drawColors[i], 0.8)
|
||||
lineColor && (color = lineColor)
|
||||
|
||||
let tureLineType = lineType || 'line'
|
||||
const tureLineDash = tureLineType === 'dashed' ? (lineDash || defaultLineDash) : [10, 0]
|
||||
|
||||
drawLineFun(ctx, points, 1, color, false, tureLineDash, true, true)
|
||||
},
|
||||
drawFills () {
|
||||
const { data: { data }, valuePointPos, drawFill } = this
|
||||
|
||||
data.forEach((line, i) => drawFill(line, valuePointPos[i]))
|
||||
},
|
||||
drawFill ({ fillColor, type, data }, points) {
|
||||
if (!fillColor) return
|
||||
|
||||
const { canvas: { drawPolylinePath, drawSmoothlinePath } } = this
|
||||
|
||||
const { ctx, getGradientColor, filterNull, axisOriginPos: [, y] } = this
|
||||
|
||||
let drawLineFun = drawPolylinePath
|
||||
type === 'smoothline' && (drawLineFun = drawSmoothlinePath)
|
||||
|
||||
const maxValue = Math.max(...filterNull(data))
|
||||
const maxValueIndex = data.findIndex(v => v === maxValue)
|
||||
|
||||
const color = getGradientColor(points[maxValueIndex], fillColor)
|
||||
|
||||
const lastPoint = points[points.length - 1]
|
||||
|
||||
ctx.fillStyle = color
|
||||
|
||||
drawLineFun(ctx, points, false, true, true)
|
||||
|
||||
ctx.lineTo(lastPoint[0], y)
|
||||
ctx.lineTo(points[0][0], y)
|
||||
|
||||
ctx.closePath()
|
||||
|
||||
ctx.fill()
|
||||
},
|
||||
getGradientColor (value, colors) {
|
||||
const { data: { localGradient }, axisAnglePos, horizon } = this
|
||||
|
||||
const { ctx, canvas: { getLinearGradientColor } } = this
|
||||
|
||||
if (localGradient) {
|
||||
return getLinearGradientColor(ctx,
|
||||
...(horizon
|
||||
? [value, [axisAnglePos.leftTop[0], value[1]]]
|
||||
: [value, [value[0], axisAnglePos.leftBottom[1]]]),
|
||||
colors)
|
||||
} else {
|
||||
return getLinearGradientColor(ctx,
|
||||
...(horizon
|
||||
? [axisAnglePos.leftTop, axisAnglePos.rightTop]
|
||||
: [axisAnglePos.leftTop, axisAnglePos.leftBottom]),
|
||||
colors)
|
||||
}
|
||||
},
|
||||
drawPoints () {
|
||||
const { data: { data }, valuePointPos, drawPoint } = this
|
||||
|
||||
data.forEach((line, i) => drawPoint(line, valuePointPos[i], i))
|
||||
},
|
||||
drawPoint ({ pointColor }, points, i) {
|
||||
const { ctx, drawColors, defaultPointRadius } = this
|
||||
|
||||
const { canvas: { drawPoints: drawPFun } } = this
|
||||
|
||||
const color = pointColor || drawColors[i]
|
||||
|
||||
drawPFun(ctx, points, defaultPointRadius, color)
|
||||
},
|
||||
drawValues () {
|
||||
const { ctx, data: { data, showValueText, valueTextOffset, valueTextFontSize } } = this
|
||||
|
||||
if (!showValueText) return
|
||||
|
||||
const { defaultValueFontSize, drawValue } = this
|
||||
|
||||
const offset = valueTextOffset || [0, -5]
|
||||
|
||||
ctx.font = `${valueTextFontSize || defaultValueFontSize}px Arial`
|
||||
|
||||
ctx.textAlign = 'center'
|
||||
ctx.textBaseline = 'bottom'
|
||||
|
||||
data.forEach((line, i) => drawValue(line, i, offset))
|
||||
},
|
||||
drawValue ({ data, valueTextColor, lineColor, pointColor, fillColor }, i, offset) {
|
||||
const { ctx, getOffsetPoints, valuePointPos, drawColors, defaultValueColor } = this
|
||||
|
||||
const { data: { valueTextColor: outerValueTC } } = this
|
||||
|
||||
const drawColorsNum = drawColors.length
|
||||
|
||||
let currentColor = valueTextColor
|
||||
currentColor === 'inherit' && (currentColor = pointColor || lineColor || fillColor || drawColors[i % drawColorsNum])
|
||||
currentColor instanceof Array && (currentColor = currentColor[0])
|
||||
|
||||
ctx.fillStyle = currentColor || outerValueTC || defaultValueColor
|
||||
|
||||
const pointsPos = valuePointPos[i]
|
||||
|
||||
getOffsetPoints(pointsPos, offset).forEach((pos, i) => {
|
||||
if (!data[i] && data[i] !== 0) return
|
||||
|
||||
ctx.fillText(data[i], ...pos)
|
||||
})
|
||||
},
|
||||
getOffsetPoint ([x, y], [ox, oy]) {
|
||||
return [x + ox, y + oy]
|
||||
},
|
||||
getOffsetPoints (points, offset) {
|
||||
const { getOffsetPoint } = this
|
||||
|
||||
return points.map(point => point ? getOffsetPoint(point, offset) : false)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.polyline-chart {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.canvas-container {
|
||||
flex: 1;
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,547 +0,0 @@
|
||||
<template>
|
||||
<div class="radar-chart">
|
||||
|
||||
<loading v-if="!data" />
|
||||
|
||||
<div class="canvas-container">
|
||||
<canvas :ref="ref" />
|
||||
</div>
|
||||
|
||||
<label-line :label="data.labelLine" :colors="drawColors" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import colorsMixin from '../../mixins/colorsMixin.js'
|
||||
|
||||
import canvasMixin from '../../mixins/canvasMixin.js'
|
||||
|
||||
export default {
|
||||
name: 'RadarChart',
|
||||
mixins: [canvasMixin, colorsMixin],
|
||||
data () {
|
||||
return {
|
||||
ref: `radar-chart-${(new Date()).getTime()}`,
|
||||
|
||||
defaultRadius: 0.8,
|
||||
defaultRingNum: 4,
|
||||
defaultRingType: 'circle',
|
||||
defaultRingLineType: 'dashed',
|
||||
defaultRingLineColor: '#666',
|
||||
defaultRingFillType: 'none',
|
||||
defaultRayLineType: 'line',
|
||||
defaultRayLineColor: '#666',
|
||||
|
||||
defaultRayLineOffset: Math.PI * -0.5,
|
||||
defaultLabelColor: '#fff',
|
||||
defaultLabelFS: 10,
|
||||
|
||||
defaultValueFontSize: 10,
|
||||
defaultValueColor: '#999',
|
||||
|
||||
drawColors: '',
|
||||
radius: '',
|
||||
ringType: '',
|
||||
rayLineRadianData: [],
|
||||
ringRadiusData: [],
|
||||
ringPolylineData: [],
|
||||
ringLineDash: [],
|
||||
ringlineMultipleColor: false,
|
||||
ringLineColor: '',
|
||||
ringFillType: '',
|
||||
ringFillMultipleColor: false,
|
||||
ringFillColor: '',
|
||||
rayLineColor: '',
|
||||
rayLineDash: '',
|
||||
rayLineMultipleColor: false,
|
||||
labelPosData: [],
|
||||
labelColor: '',
|
||||
labelFontSize: '',
|
||||
labelMultipleColor: false,
|
||||
|
||||
valuePointData: []
|
||||
}
|
||||
},
|
||||
props: ['data', 'colors'],
|
||||
watch: {
|
||||
data (d) {
|
||||
const { reDraw } = this
|
||||
|
||||
reDraw(d)
|
||||
},
|
||||
color (d) {
|
||||
const { reDraw } = this
|
||||
|
||||
reDraw(d)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async init () {
|
||||
const { initCanvas, data, draw } = this
|
||||
|
||||
await initCanvas()
|
||||
|
||||
data && draw()
|
||||
},
|
||||
draw () {
|
||||
const { ctx, canvasWH } = this
|
||||
|
||||
ctx.clearRect(0, 0, ...canvasWH)
|
||||
|
||||
const { initColors, calcRadarRadius, calcRingType } = this
|
||||
|
||||
initColors()
|
||||
|
||||
calcRadarRadius()
|
||||
|
||||
calcRingType()
|
||||
|
||||
const { calcRayLineRadianData, calcRingRadiusData, calcRingPolylineData } = this
|
||||
|
||||
calcRayLineRadianData()
|
||||
|
||||
calcRingRadiusData()
|
||||
|
||||
calcRingPolylineData()
|
||||
|
||||
const { calcRingDrawConfig, calcRingFillConfig, fillRing } = this
|
||||
|
||||
calcRingDrawConfig()
|
||||
|
||||
calcRingFillConfig()
|
||||
|
||||
fillRing()
|
||||
|
||||
const { drawCircleRing, drawPolylineRing, calcRayLineConfig } = this
|
||||
|
||||
drawCircleRing()
|
||||
|
||||
drawPolylineRing()
|
||||
|
||||
calcRayLineConfig()
|
||||
|
||||
const { drawRayLine, calcLabelPosData, calcLabelConfig } = this
|
||||
|
||||
drawRayLine()
|
||||
|
||||
calcLabelPosData()
|
||||
|
||||
calcLabelConfig()
|
||||
|
||||
const { drawLable, caclValuePointData, fillRadar } = this
|
||||
|
||||
drawLable()
|
||||
|
||||
caclValuePointData()
|
||||
|
||||
fillRadar()
|
||||
|
||||
const { fillValueText } = this
|
||||
|
||||
fillValueText()
|
||||
},
|
||||
calcRadarRadius () {
|
||||
const { canvasWH, data: { radius }, defaultRadius } = this
|
||||
|
||||
this.radius = Math.min(...canvasWH) * (radius || defaultRadius) * 0.5
|
||||
},
|
||||
calcRingType () {
|
||||
const { data: { ringType }, defaultRingType } = this
|
||||
|
||||
this.ringType = ringType || defaultRingType
|
||||
},
|
||||
calcRayLineRadianData () {
|
||||
const { data: { label, rayLineOffset }, defaultRayLineOffset } = this
|
||||
|
||||
const { data } = label
|
||||
|
||||
const fullRadian = Math.PI * 2
|
||||
|
||||
const radianGap = fullRadian / data.length
|
||||
|
||||
const radianOffset = rayLineOffset || defaultRayLineOffset
|
||||
|
||||
this.rayLineRadianData = data.map((t, i) => radianGap * i + radianOffset)
|
||||
},
|
||||
calcRingRadiusData () {
|
||||
const { data: { ringNum }, defaultRingNum, radius } = this
|
||||
|
||||
const num = ringNum || defaultRingNum
|
||||
|
||||
const radiusGap = radius / num
|
||||
|
||||
this.ringRadiusData = new Array(num).fill(0).map((t, i) =>
|
||||
radiusGap * (i + 1))
|
||||
},
|
||||
calcRingPolylineData () {
|
||||
const { ringRadiusData, rayLineRadianData, centerPos } = this
|
||||
|
||||
const { canvas: { getCircleRadianPoint } } = this
|
||||
|
||||
this.ringPolylineData = ringRadiusData.map((r, i) =>
|
||||
rayLineRadianData.map(radian =>
|
||||
getCircleRadianPoint(...centerPos, r, radian)))
|
||||
},
|
||||
calcRingDrawConfig () {
|
||||
const { defaultRingLineType, defaultRingLineColor } = this
|
||||
|
||||
const { data: { ringLineType, ringLineColor }, drawColors } = this
|
||||
|
||||
this.ringLineDash = (ringLineType || defaultRingLineType) === 'dashed' ? [5, 5] : [10, 0]
|
||||
|
||||
const trueRingLineColor = ringLineColor === 'colors' ? drawColors : ringLineColor
|
||||
|
||||
this.ringlineMultipleColor = typeof trueRingLineColor === 'object'
|
||||
|
||||
this.ringLineColor = trueRingLineColor || defaultRingLineColor
|
||||
},
|
||||
calcRingFillConfig () {
|
||||
const { data: { ringFillType, ringFillColor }, defaultRingFillType, drawColors } = this
|
||||
|
||||
this.ringFillType = ringFillType || defaultRingFillType
|
||||
|
||||
const trueRingFillColor = this.ringFillColor = (!ringFillColor || ringFillColor === 'colors') ? drawColors : ringFillColor
|
||||
|
||||
this.ringFillMultipleColor = typeof trueRingFillColor === 'object'
|
||||
},
|
||||
fillRing () {
|
||||
const { ringFillType, fillCoverRing, fillMulCoverRing, fillRingRing } = this
|
||||
|
||||
switch (ringFillType) {
|
||||
case 'cover': fillCoverRing()
|
||||
break
|
||||
|
||||
case 'mulCover': fillMulCoverRing()
|
||||
break
|
||||
|
||||
case 'ring': fillRingRing()
|
||||
break
|
||||
}
|
||||
},
|
||||
fillCoverRing () {
|
||||
const { ctx, centerPos, ringFillColor, ringType, radius, ringPolylineData } = this
|
||||
|
||||
const { canvas: { getRadialGradientColor, drawPolylinePath } } = this
|
||||
|
||||
const color = getRadialGradientColor(ctx, centerPos, 0, radius, ringFillColor)
|
||||
|
||||
ctx.beginPath()
|
||||
|
||||
ringType === 'circle' && ctx.arc(...centerPos, radius, 0, Math.PI * 2)
|
||||
|
||||
ringType === 'polyline' && drawPolylinePath(ctx, ringPolylineData[ringPolylineData.length - 1])
|
||||
|
||||
ctx.closePath()
|
||||
|
||||
ctx.fillStyle = color
|
||||
|
||||
ctx.fill()
|
||||
},
|
||||
fillMulCoverRing () {
|
||||
const { ctx, ringType, ringFillColor, centerPos } = this
|
||||
|
||||
const { ringFillMultipleColor, ringPolylineData, ringRadiusData, deepClone } = this
|
||||
|
||||
const { canvas: { drawPolylinePath } } = this
|
||||
|
||||
!ringFillMultipleColor && (ctx.fillStyle = ringFillColor)
|
||||
|
||||
const colorNum = ringFillColor.length
|
||||
|
||||
const LastRingIndex = ringRadiusData.length - 1
|
||||
|
||||
ringType === 'circle' &&
|
||||
deepClone(ringRadiusData).reverse().forEach((radius, i) => {
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.arc(...centerPos, radius, 0, Math.PI * 2)
|
||||
|
||||
ringFillMultipleColor && (ctx.fillStyle = ringFillColor[(LastRingIndex - i) % colorNum])
|
||||
|
||||
ctx.fill()
|
||||
})
|
||||
|
||||
ringType === 'polyline' &&
|
||||
deepClone(ringPolylineData).reverse().forEach((line, i) => {
|
||||
drawPolylinePath(ctx, line, true, true)
|
||||
|
||||
ringFillMultipleColor && (ctx.fillStyle = ringFillColor[(LastRingIndex - i) % colorNum])
|
||||
|
||||
ctx.fill()
|
||||
})
|
||||
},
|
||||
fillRingRing () {
|
||||
const { ctx, ringType, ringRadiusData, rayLineRadianData, getPointToLineDistance } = this
|
||||
|
||||
const { ringFillMultipleColor, centerPos, ringFillColor, ringPolylineData } = this
|
||||
|
||||
const { canvas: { drawPolylinePath, getCircleRadianPoint } } = this
|
||||
|
||||
let lineWidth = ctx.lineWidth = ringRadiusData[0]
|
||||
|
||||
const halfLineWidth = lineWidth / 2
|
||||
|
||||
const colorNum = ringFillColor.length
|
||||
|
||||
!ringFillMultipleColor && (ctx.strokeStyle = ringFillColor)
|
||||
|
||||
ringType === 'circle' &&
|
||||
ringRadiusData.forEach((r, i) => {
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.arc(...centerPos, r - halfLineWidth, 0, Math.PI * 2)
|
||||
|
||||
ringFillMultipleColor && (ctx.strokeStyle = ringFillColor[i % colorNum])
|
||||
|
||||
ctx.stroke()
|
||||
})
|
||||
|
||||
ctx.lineCap = 'round'
|
||||
|
||||
ctx.lineWidth = getPointToLineDistance(centerPos, ringPolylineData[0][0], ringPolylineData[0][1])
|
||||
|
||||
ringType === 'polyline' &&
|
||||
ringRadiusData.map(r => r - halfLineWidth).map(r =>
|
||||
rayLineRadianData.map(radian =>
|
||||
getCircleRadianPoint(...centerPos, r, radian))).forEach((line, i) => {
|
||||
drawPolylinePath(ctx, line, true, true)
|
||||
|
||||
ringFillMultipleColor && (ctx.strokeStyle = ringFillColor[i % colorNum])
|
||||
|
||||
ctx.stroke()
|
||||
})
|
||||
},
|
||||
drawCircleRing () {
|
||||
const { data: { ringType }, defaultRingType } = this
|
||||
|
||||
if ((ringType && ringType !== 'circle') || (!ringType && defaultRingType !== 'circle')) return
|
||||
|
||||
const { ctx, ringRadiusData, centerPos, ringLineDash, ringlineMultipleColor, ringLineColor } = this
|
||||
|
||||
ctx.setLineDash(ringLineDash)
|
||||
|
||||
ctx.lineWidth = 1
|
||||
|
||||
!ringlineMultipleColor && (ctx.strokeStyle = ringLineColor)
|
||||
|
||||
const colorNum = ringLineColor.length
|
||||
|
||||
ringRadiusData.forEach((r, i) => {
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.arc(...centerPos, r, 0, Math.PI * 2)
|
||||
|
||||
ringlineMultipleColor && (ctx.strokeStyle = ringLineColor[i % colorNum])
|
||||
|
||||
ctx.stroke()
|
||||
})
|
||||
},
|
||||
drawPolylineRing () {
|
||||
const { data: { ringType }, defaultRingType } = this
|
||||
|
||||
if ((ringType && ringType !== 'polyline') || (!ringType && defaultRingType !== 'polyline')) return
|
||||
|
||||
const { ctx, ringPolylineData, ringLineDash, ringlineMultipleColor, ringLineColor } = this
|
||||
|
||||
const { canvas: { drawPolyline } } = this
|
||||
|
||||
const colorNum = ringLineColor.length
|
||||
|
||||
ringPolylineData.forEach((line, i) =>
|
||||
drawPolyline(ctx, line, 1,
|
||||
(ringlineMultipleColor ? ringLineColor[i % colorNum] : ringLineColor),
|
||||
true, ringLineDash, true))
|
||||
},
|
||||
calcRayLineConfig () {
|
||||
const { data: { rayLineType, rayLineColor }, defaultRayLineType, defaultRayLineColor, drawColors } = this
|
||||
|
||||
this.rayLineDash = (rayLineType || defaultRayLineType) === 'line' ? [10, 0] : [5, 5]
|
||||
|
||||
const trueRayLineColor = rayLineColor === 'colors' ? drawColors : (rayLineColor || defaultRayLineColor)
|
||||
|
||||
this.rayLineColor = trueRayLineColor
|
||||
|
||||
this.rayLineMultipleColor = typeof trueRayLineColor === 'object'
|
||||
},
|
||||
drawRayLine () {
|
||||
const { ctx, rayLineColor, rayLineDash, ringPolylineData, centerPos, rayLineMultipleColor } = this
|
||||
|
||||
const lastRingLineIndex = ringPolylineData.length - 1
|
||||
|
||||
ctx.setLineDash(rayLineDash)
|
||||
|
||||
!rayLineMultipleColor && (ctx.strokeStyle = rayLineColor)
|
||||
|
||||
ctx.lineWidth = 1
|
||||
|
||||
const colorNum = rayLineColor.length
|
||||
|
||||
ringPolylineData[lastRingLineIndex].forEach((point, i) => {
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.moveTo(...centerPos)
|
||||
|
||||
ctx.lineTo(...point)
|
||||
|
||||
rayLineMultipleColor && (ctx.strokeStyle = rayLineColor[i % colorNum])
|
||||
|
||||
ctx.stroke()
|
||||
})
|
||||
},
|
||||
calcLabelPosData () {
|
||||
const { rayLineRadianData, radius, centerPos } = this
|
||||
|
||||
const { canvas: { getCircleRadianPoint } } = this
|
||||
|
||||
const labelRadius = radius + 10
|
||||
|
||||
this.labelPosData = rayLineRadianData.map(radian =>
|
||||
getCircleRadianPoint(...centerPos, labelRadius, radian))
|
||||
},
|
||||
calcLabelConfig () {
|
||||
const { defaultLabelColor, defaultLabelFS, drawColors } = this
|
||||
|
||||
const { data: { label: { color, fontSize } } } = this
|
||||
|
||||
const trueLabelColor = color === 'colors' ? drawColors : (color || defaultLabelColor)
|
||||
|
||||
this.labelMultipleColor = typeof trueLabelColor === 'object'
|
||||
|
||||
this.labelFontSize = fontSize || defaultLabelFS
|
||||
|
||||
this.labelColor = trueLabelColor
|
||||
},
|
||||
drawLable () {
|
||||
const { ctx, centerPos: [x], labelPosData, labelColor, labelFontSize, labelMultipleColor } = this
|
||||
|
||||
const { data: { label: { data } } } = this
|
||||
|
||||
ctx.font = `${labelFontSize}px Arial`
|
||||
|
||||
!labelMultipleColor && (ctx.fillStyle = labelColor)
|
||||
|
||||
ctx.textBaseline = 'middle'
|
||||
|
||||
const colorNum = labelColor.length
|
||||
|
||||
labelPosData.forEach((pos, i) => {
|
||||
ctx.textAlign = 'start'
|
||||
|
||||
pos[0] < x && (ctx.textAlign = 'end')
|
||||
|
||||
labelMultipleColor && (ctx.fillStyle = labelColor[i % colorNum])
|
||||
|
||||
ctx.fillText(data[i], ...pos)
|
||||
})
|
||||
},
|
||||
caclValuePointData () {
|
||||
const { data: { data, max }, centerPos, radius, rayLineRadianData } = this
|
||||
|
||||
const { canvas: { getCircleRadianPoint } } = this
|
||||
|
||||
const maxValue = max || Math.max(...data.map(({ data: td }) => Math.max(...td)))
|
||||
|
||||
const valueRadius = data.map(({ data: td }) =>
|
||||
td.map(value =>
|
||||
Number.isFinite(value)
|
||||
? value / maxValue * radius : false))
|
||||
|
||||
this.valuePointData = valueRadius.map(td =>
|
||||
td.map((r, i) =>
|
||||
r ? getCircleRadianPoint(...centerPos, r, rayLineRadianData[i]) : false))
|
||||
},
|
||||
fillRadar () {
|
||||
const { ctx, data: { data }, valuePointData, drawColors, filterNull } = this
|
||||
|
||||
const { canvas: { drawPolylinePath } } = this
|
||||
|
||||
const { color: { hexToRgb } } = this
|
||||
|
||||
const colorNum = drawColors.length
|
||||
|
||||
valuePointData.forEach((line, i) => {
|
||||
const currentColor = drawColors[i % colorNum]
|
||||
|
||||
const lineColor = data[i].lineColor
|
||||
const fillColor = data[i].fillColor
|
||||
|
||||
data[i].dashed ? ctx.setLineDash([5, 5]) : ctx.setLineDash([10, 0])
|
||||
|
||||
drawPolylinePath(ctx, filterNull(line), 1, true, true)
|
||||
|
||||
ctx.strokeStyle = lineColor || currentColor
|
||||
|
||||
ctx.stroke()
|
||||
|
||||
ctx.fillStyle = fillColor || hexToRgb(currentColor, 0.5)
|
||||
|
||||
ctx.fill()
|
||||
})
|
||||
},
|
||||
fillValueText () {
|
||||
const { data: { data, showValueText, valueTextFontSize } } = this
|
||||
|
||||
if (!showValueText) return
|
||||
|
||||
const { ctx, defaultValueFontSize } = this
|
||||
|
||||
ctx.font = `${valueTextFontSize || defaultValueFontSize}px Arial`
|
||||
|
||||
const { fillSeriesText } = this
|
||||
|
||||
data.forEach((item, i) => fillSeriesText(item, i))
|
||||
},
|
||||
fillSeriesText ({ valueTextColor, lineColor, fillColor, data }, i) {
|
||||
const { ctx, drawColors, valuePointData, drawTexts } = this
|
||||
|
||||
const { data: { valueTextOffset, valueTextColor: outerValueTC }, defaultValueColor } = this
|
||||
|
||||
const trueOffset = valueTextOffset || [5, -5]
|
||||
|
||||
const drawColorsNum = drawColors.length
|
||||
|
||||
let currentColor = valueTextColor
|
||||
currentColor === 'inherit' && (currentColor = lineColor || fillColor || drawColors[i % drawColorsNum])
|
||||
currentColor instanceof Array && (currentColor = currentColor[0])
|
||||
|
||||
ctx.fillStyle = currentColor || outerValueTC || defaultValueColor
|
||||
|
||||
drawTexts(ctx, data, valuePointData[i], trueOffset)
|
||||
},
|
||||
drawTexts (ctx, values, points, [x, y] = [0, 0]) {
|
||||
values.forEach((v, i) => {
|
||||
if (!v && v !== 0) return
|
||||
|
||||
ctx.fillText(v, points[i][0] + x, points[i][1] + y)
|
||||
})
|
||||
},
|
||||
reDraw (d) {
|
||||
const { draw } = this
|
||||
|
||||
d && draw()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.radar-chart {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.canvas-container {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,463 +0,0 @@
|
||||
<template>
|
||||
<div class="ring-chart">
|
||||
<canvas :ref="ref" />
|
||||
|
||||
<loading v-if="!data" />
|
||||
|
||||
<template v-else>
|
||||
<div class="center-info" v-if="data.active">
|
||||
<div class="percent-show">{{percent}}</div>
|
||||
<div class="current-label" :ref="labelRef">{{data.data[activeIndex].title}}</div>
|
||||
</div>
|
||||
|
||||
<div class="label-line">
|
||||
<div class="label-container">
|
||||
|
||||
<div class="label" v-for="(label, index) in data.data" :key="label.title">
|
||||
<div :style="`background-color: ${data.color[index % data.data.length]}`" />
|
||||
<div>{{ label.title }}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'RingChart',
|
||||
props: ['data'],
|
||||
data () {
|
||||
return {
|
||||
ref: `ring-chart-${(new Date()).getTime()}`,
|
||||
canvasDom: '',
|
||||
canvasWH: [0, 0],
|
||||
ctx: '',
|
||||
|
||||
labelRef: `label-ref-${(new Date()).getTime()}`,
|
||||
labelDom: '',
|
||||
|
||||
ringRadius: '',
|
||||
ringOriginPos: [0, 0],
|
||||
ringLineWidth: '',
|
||||
maxRingWidthP: 1.15,
|
||||
|
||||
activeIndex: 1,
|
||||
activePercent: 1,
|
||||
activeAddStatus: true,
|
||||
|
||||
arcData: [],
|
||||
radiusData: [],
|
||||
aroundLineData: [],
|
||||
aroundTextData: [],
|
||||
aroundTextFont: '13px Arial',
|
||||
|
||||
activeIncrease: 0.005,
|
||||
activeTime: 4500,
|
||||
|
||||
offsetAngle: Math.PI * 0.5 * -1,
|
||||
|
||||
percent: 0,
|
||||
totalValue: 0,
|
||||
|
||||
activeAnimationHandler: '',
|
||||
awaitActiveHandler: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
data (d) {
|
||||
const { reDraw } = this
|
||||
|
||||
if (!d) return
|
||||
|
||||
reDraw()
|
||||
},
|
||||
activeIndex () {
|
||||
const { doPercentAnimation, doLabelTextAnimation } = this
|
||||
|
||||
doPercentAnimation()
|
||||
|
||||
doLabelTextAnimation()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const { $nextTick, initCanvas, calcRingConfig, data, draw } = this
|
||||
|
||||
$nextTick(e => {
|
||||
initCanvas()
|
||||
|
||||
calcRingConfig()
|
||||
|
||||
data && draw()
|
||||
})
|
||||
},
|
||||
initCanvas () {
|
||||
const { $refs, ref, labelRef, canvasWH } = this
|
||||
|
||||
const canvas = this.canvasDom = $refs[ref]
|
||||
|
||||
this.labelDom = $refs[labelRef]
|
||||
|
||||
canvasWH[0] = canvas.clientWidth
|
||||
canvasWH[1] = canvas.clientHeight
|
||||
|
||||
canvas.setAttribute('width', canvasWH[0])
|
||||
canvas.setAttribute('height', canvasWH[1])
|
||||
|
||||
this.ctx = canvas.getContext('2d')
|
||||
},
|
||||
calcRingConfig () {
|
||||
const { canvasWH, ringOriginPos } = this
|
||||
|
||||
ringOriginPos[0] = canvasWH[0] / 2
|
||||
ringOriginPos[1] = (canvasWH[1] - 30) / 2
|
||||
|
||||
const ringRadius = this.ringRadius = Math.min(...canvasWH) * 0.6 / 2
|
||||
|
||||
this.ringLineWidth = ringRadius * 0.3
|
||||
},
|
||||
draw () {
|
||||
const { ctx, canvasWH } = this
|
||||
|
||||
ctx.clearRect(0, 0, ...canvasWH)
|
||||
|
||||
const { caclArcData, data: { active }, drawActive, drwaStatic } = this
|
||||
|
||||
caclArcData()
|
||||
|
||||
active ? drawActive() : drwaStatic()
|
||||
},
|
||||
caclArcData () {
|
||||
const { data: { data } } = this
|
||||
|
||||
const { getTotalValue, offsetAngle } = this
|
||||
|
||||
const totalValue = getTotalValue()
|
||||
|
||||
const full = 2 * Math.PI
|
||||
|
||||
const aveAngle = full / data.length
|
||||
|
||||
let currentPercent = offsetAngle
|
||||
|
||||
this.arcData = []
|
||||
|
||||
data.forEach(({ value }) => {
|
||||
const valueAngle = totalValue === 0 ? aveAngle : value / totalValue * full
|
||||
|
||||
this.arcData.push([
|
||||
currentPercent,
|
||||
currentPercent += valueAngle
|
||||
])
|
||||
})
|
||||
},
|
||||
getTotalValue () {
|
||||
const { data: { data } } = this
|
||||
|
||||
let totalValue = 0
|
||||
|
||||
data.forEach(({ value }) => (totalValue += value))
|
||||
|
||||
this.totalValue = totalValue
|
||||
|
||||
return totalValue
|
||||
},
|
||||
drawActive () {
|
||||
const { ctx, canvasWH } = this
|
||||
|
||||
ctx.clearRect(0, 0, ...canvasWH)
|
||||
|
||||
const { calcRadiusData, drawRing, drawActive } = this
|
||||
|
||||
calcRadiusData()
|
||||
|
||||
drawRing()
|
||||
|
||||
this.activeAnimationHandler = requestAnimationFrame(drawActive)
|
||||
},
|
||||
calcRadiusData () {
|
||||
const { arcData, activeAddStatus, activePercent, activeIncrease, activeIndex } = this
|
||||
|
||||
const radiusData = new Array(arcData.length).fill(1)
|
||||
|
||||
const activeRadius = (activeAddStatus ? this.activePercent += activeIncrease : activePercent)
|
||||
|
||||
radiusData[activeIndex] = activeRadius
|
||||
|
||||
const { maxRingWidthP, ringRadius, awaitActive } = this
|
||||
|
||||
const prevRadius = maxRingWidthP - activeRadius + 1
|
||||
|
||||
const prevIndex = activeIndex - 1
|
||||
|
||||
radiusData[prevIndex < 0 ? arcData.length - 1 : prevIndex] = prevRadius
|
||||
|
||||
this.radiusData = radiusData.map(v => (v * ringRadius))
|
||||
|
||||
if (activeRadius >= maxRingWidthP && activeAddStatus) awaitActive()
|
||||
},
|
||||
awaitActive () {
|
||||
const { activeTime, turnToNextActive } = this
|
||||
|
||||
this.activeAddStatus = false
|
||||
|
||||
this.awaitActiveHandler = setTimeout(turnToNextActive, activeTime)
|
||||
},
|
||||
turnToNextActive () {
|
||||
const { arcData, activeIndex } = this
|
||||
|
||||
this.activePercent = 1
|
||||
|
||||
this.activeIndex = (activeIndex + 1 === arcData.length ? 0 : activeIndex + 1)
|
||||
|
||||
this.activeAddStatus = true
|
||||
},
|
||||
drawRing () {
|
||||
const { arcData, ctx, ringOriginPos, radiusData } = this
|
||||
|
||||
const { ringLineWidth, data: { color } } = this
|
||||
|
||||
const arcNum = arcData.length
|
||||
|
||||
arcData.forEach((arc, i) => {
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.arc(...ringOriginPos, radiusData[i], ...arc)
|
||||
|
||||
ctx.lineWidth = ringLineWidth
|
||||
|
||||
ctx.strokeStyle = color[i % arcNum]
|
||||
|
||||
ctx.stroke()
|
||||
})
|
||||
},
|
||||
doPercentAnimation () {
|
||||
const { totalValue, percent, activeIndex, data: { data }, doPercentAnimation } = this
|
||||
|
||||
if (!totalValue) return
|
||||
|
||||
const currentValue = data[activeIndex].value
|
||||
|
||||
let currentPercent = Math.trunc(currentValue / totalValue * 100)
|
||||
|
||||
currentPercent === 0 && (currentPercent = 1)
|
||||
currentValue === 0 && (currentPercent = 0)
|
||||
|
||||
if (currentPercent === percent) return
|
||||
|
||||
currentPercent > percent ? this.percent++ : this.percent--
|
||||
|
||||
setTimeout(doPercentAnimation, 10)
|
||||
},
|
||||
doLabelTextAnimation () {
|
||||
let { labelDom, $refs, labelRef } = this
|
||||
|
||||
if (!labelDom) labelDom = this.labelDom = $refs[labelRef]
|
||||
|
||||
labelDom.setAttribute('class', 'current-label transform-text')
|
||||
|
||||
setTimeout(() => {
|
||||
labelDom.setAttribute('class', 'current-label')
|
||||
}, 2000)
|
||||
},
|
||||
drwaStatic () {
|
||||
const { drawStaticRing, calcAroundLineData, drawAroundLine, calcAroundTextData, drawAroundText } = this
|
||||
|
||||
drawStaticRing()
|
||||
|
||||
calcAroundLineData()
|
||||
|
||||
drawAroundLine()
|
||||
|
||||
calcAroundTextData()
|
||||
|
||||
drawAroundText()
|
||||
},
|
||||
drawStaticRing () {
|
||||
const { arcData, ringRadius, drawRing } = this
|
||||
|
||||
this.radiusData = new Array(arcData.length).fill(1).map(v => v * ringRadius)
|
||||
|
||||
drawRing()
|
||||
},
|
||||
calcAroundLineData () {
|
||||
const { arcData, ringRadius, ringLineWidth, ringOriginPos: [x, y], data: { data }, canvas, totalValue } = this
|
||||
|
||||
const { getCircleRadianPoint } = canvas
|
||||
|
||||
const radian = arcData.map(([a, b]) => (a + (b - a) / 2))
|
||||
|
||||
const radius = ringRadius + ringLineWidth / 2
|
||||
|
||||
const aroundLineData = radian.map(r => getCircleRadianPoint(x, y, radius, r))
|
||||
|
||||
const lineLength = 35
|
||||
|
||||
this.aroundLineData = aroundLineData.map(([bx, by], i) => {
|
||||
if (!data[i].value && totalValue) return [false, false]
|
||||
|
||||
const lineEndXPos = (bx > x ? bx + lineLength : bx - lineLength)
|
||||
|
||||
return [
|
||||
[bx, by],
|
||||
[lineEndXPos, by]
|
||||
]
|
||||
})
|
||||
},
|
||||
drawAroundLine () {
|
||||
const { aroundLineData, data: { color }, ctx, canvas: { drawLine } } = this
|
||||
|
||||
const colorNum = color.length
|
||||
|
||||
aroundLineData.forEach(([lineBegin, lineEnd], i) =>
|
||||
lineBegin !== false &&
|
||||
drawLine(ctx, lineBegin, lineEnd, 1, color[i % colorNum]))
|
||||
},
|
||||
calcAroundTextData () {
|
||||
const { data: { data, fixed }, totalValue } = this
|
||||
|
||||
const aroundTextData = this.aroundTextData = []
|
||||
|
||||
if (!totalValue) return data.forEach(({ v, title }, i) => aroundTextData.push([0, title]))
|
||||
|
||||
const dataLast = data.length - 1
|
||||
|
||||
let totalPercent = 0
|
||||
|
||||
data.forEach(({ value, title }, i) => {
|
||||
if (!value) return aroundTextData.push([false, false])
|
||||
|
||||
let percent = Number((value / totalValue * 100).toFixed(fixed || 1))
|
||||
|
||||
percent < 0.1 && (percent = 0.1)
|
||||
|
||||
const currentPercent = (i === dataLast ? 100 - totalPercent : percent).toFixed(fixed || 1)
|
||||
|
||||
aroundTextData.push([currentPercent, title])
|
||||
|
||||
totalPercent += percent
|
||||
})
|
||||
},
|
||||
drawAroundText () {
|
||||
const { ctx, aroundTextData, aroundTextFont, aroundLineData, ringOriginPos: [x] } = this
|
||||
|
||||
ctx.font = aroundTextFont
|
||||
ctx.fillStyle = '#fff'
|
||||
|
||||
aroundTextData.forEach(([percent, title], i) => {
|
||||
if (percent === false) return
|
||||
|
||||
const currentPos = aroundLineData[i][1]
|
||||
|
||||
ctx.textAlign = 'start'
|
||||
|
||||
currentPos[0] < x && (ctx.textAlign = 'end')
|
||||
|
||||
ctx.textBaseline = 'bottom'
|
||||
ctx.fillText(`${percent}%`, ...currentPos)
|
||||
|
||||
ctx.textBaseline = 'top'
|
||||
ctx.fillText(title, ...currentPos)
|
||||
})
|
||||
},
|
||||
reDraw () {
|
||||
const { activeAnimationHandler, draw } = this
|
||||
|
||||
cancelAnimationFrame(activeAnimationHandler)
|
||||
|
||||
draw()
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.ring-chart {
|
||||
position: relative;
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.center-info {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
margin-top: -20px;
|
||||
text-align: center;
|
||||
font-family: "Microsoft Yahei", Arial, sans-serif;
|
||||
max-width: 25%;
|
||||
|
||||
.percent-show {
|
||||
font-size: 28px;
|
||||
|
||||
&::after {
|
||||
content: '%';
|
||||
font-size: 15px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.current-label {
|
||||
font-size: 16px;
|
||||
margin-top: 5%;
|
||||
transform: rotateY(0deg);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.transform-text {
|
||||
animation: transform-text 2s linear;
|
||||
}
|
||||
|
||||
@keyframes transform-text {
|
||||
to {
|
||||
transform: rotateY(360deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.label-line {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
bottom: 0px;
|
||||
font-size: 12px;
|
||||
line-height: 30px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
|
||||
.label-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.label {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 0 3px;
|
||||
height: 20px;
|
||||
|
||||
:nth-child(1) {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-top: 10px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,367 +0,0 @@
|
||||
<template>
|
||||
<div class="scroll-board" :ref="ref">
|
||||
|
||||
<loading v-if="!data" />
|
||||
|
||||
<template v-else>
|
||||
<div class="title-container"
|
||||
v-if="titleData"
|
||||
:style="`background-color:${titleTrueBG};`">
|
||||
<div :class="`title-item ${textTrueAlign[ti]}`"
|
||||
v-for="(title, ti) in titleData" :key="title + ti"
|
||||
:style="`width: ${columnTrueWidth[ti]};`">
|
||||
{{ title }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-container">
|
||||
<div :class="`row-item ${row.fade && 'fade'}`"
|
||||
:style="`height: ${rowHeight}%;background-color:${row.index % 2 === 0 ? evenTrueBG : oddTrueBG};`"
|
||||
v-for="(row, ri) in scrollData"
|
||||
:key="row.data + ri">
|
||||
|
||||
<div :class="`row-item-info ${textTrueAlign[ii]}`"
|
||||
v-for="(info, ii) in row.data"
|
||||
:key="info + Math.random()">
|
||||
|
||||
<div @click="emitClickEvent(row, ii)" :class="`rii-width ${ii === 0 && index && 'index-container'}`" :style="`width: ${columnTrueWidth[ii]};`">
|
||||
<template v-if="ii === 0 && index">
|
||||
<div class="index" :style="`background-color:${titleTrueBG};`">{{ info }}</div>
|
||||
</template>
|
||||
|
||||
<span v-else v-html="info" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'scroll-board',
|
||||
props: ['data', 'index', 'html', 'rowNum', 'titleBG', 'waitTime', 'oddBG', 'evenBG', 'columnWidth', 'textAlign', 'carousel'],
|
||||
data () {
|
||||
return {
|
||||
ref: `scroll-board-${(new Date()).getTime()}`,
|
||||
container: '',
|
||||
containerWH: [],
|
||||
|
||||
reAnimationTimer: '',
|
||||
doFadeTimer: '',
|
||||
|
||||
defaultRowNum: 5,
|
||||
defaultTitleBG: '#00BAFF',
|
||||
defaultOddBG: '#003B51',
|
||||
defaultEvenBG: '#0A2732',
|
||||
|
||||
defaultWaitTime: 2000,
|
||||
|
||||
rowTrueNum: '',
|
||||
rowHeight: '',
|
||||
titleTrueBG: '',
|
||||
oddTrueBG: '',
|
||||
evenTrueBG: '',
|
||||
columnTrueWidth: [],
|
||||
textTrueAlign: [],
|
||||
|
||||
currentIndex: 0,
|
||||
|
||||
allRowNum: 0,
|
||||
allColumnNum: 0,
|
||||
titleData: '',
|
||||
allRowData: [],
|
||||
scrollData: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
data (d) {
|
||||
const { init } = this
|
||||
|
||||
d && init()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const { data, initDom, stopAnimation, dealData, calcConfig, getCurrentScrollData } = this
|
||||
|
||||
initDom()
|
||||
|
||||
if (!data) return
|
||||
|
||||
stopAnimation()
|
||||
|
||||
dealData()
|
||||
|
||||
calcConfig()
|
||||
|
||||
getCurrentScrollData(true)
|
||||
},
|
||||
initDom () {
|
||||
const { $refs, ref } = this
|
||||
|
||||
const container = this.container = $refs[ref]
|
||||
|
||||
this.containerWH[0] = container.clientWidth
|
||||
this.containerWH[1] = container.clientHeight
|
||||
},
|
||||
dealData () {
|
||||
const { data: { data, title }, index, deepClone } = this
|
||||
|
||||
if (title) (this.titleData = index ? ['', ...title] : [...title])
|
||||
|
||||
this.allRowData = deepClone(data).map((row, i) =>
|
||||
({ index: i + 1, data: index ? [i + 1, ...row] : row }))
|
||||
},
|
||||
calcConfig () {
|
||||
const { calcAllRowColumnNum, calcRowNum, calcRowHeight } = this
|
||||
|
||||
calcAllRowColumnNum()
|
||||
|
||||
calcRowNum()
|
||||
|
||||
calcRowHeight()
|
||||
|
||||
const { calcTitleBG, oddAndEvenRowBG, calcColumnWidth } = this
|
||||
|
||||
calcTitleBG()
|
||||
|
||||
oddAndEvenRowBG()
|
||||
|
||||
calcColumnWidth()
|
||||
|
||||
const { calcTextAlign } = this
|
||||
|
||||
calcTextAlign()
|
||||
},
|
||||
calcAllRowColumnNum () {
|
||||
const { data: { data }, index } = this
|
||||
|
||||
this.allRowNum = data.length
|
||||
|
||||
this.allColumnNum = data[0].length + (index ? 1 : 0)
|
||||
},
|
||||
calcRowNum () {
|
||||
const { rowNum, defaultRowNum } = this
|
||||
|
||||
this.rowTrueNum = parseInt(rowNum || defaultRowNum)
|
||||
},
|
||||
calcRowHeight () {
|
||||
const { rowTrueNum } = this
|
||||
|
||||
this.rowHeight = 100 / rowTrueNum
|
||||
},
|
||||
calcTitleBG () {
|
||||
const { titleBG, defaultTitleBG } = this
|
||||
|
||||
this.titleTrueBG = titleBG || defaultTitleBG
|
||||
},
|
||||
oddAndEvenRowBG () {
|
||||
const { oddBG, evenBG, defaultOddBG, defaultEvenBG } = this
|
||||
|
||||
this.oddTrueBG = oddBG || defaultOddBG
|
||||
this.evenTrueBG = evenBG || defaultEvenBG
|
||||
},
|
||||
calcColumnWidth () {
|
||||
const { columnWidth, allColumnNum, filterNull, multipleSum, containerWH: [allWidth] } = this
|
||||
|
||||
const userSetColumnWidth = columnWidth || []
|
||||
|
||||
const setColumnData = filterNull(userSetColumnWidth)
|
||||
|
||||
const useWidth = multipleSum(...setColumnData.map(w => parseInt(w)))
|
||||
|
||||
const avgNum = allColumnNum - setColumnData.length
|
||||
|
||||
const avgWidth = (allWidth - useWidth) / avgNum + 'px'
|
||||
|
||||
this.columnTrueWidth = new Array(allColumnNum).fill(0).map((t, i) =>
|
||||
userSetColumnWidth[i] ? `${userSetColumnWidth[i]}px` : avgWidth)
|
||||
},
|
||||
calcTextAlign () {
|
||||
const { textAlign, allColumnNum, index } = this
|
||||
|
||||
const userSetTextAlign = textAlign || []
|
||||
|
||||
const textTrueAlign = new Array(allColumnNum).fill('left').map((d, i) =>
|
||||
userSetTextAlign[i] || d)
|
||||
|
||||
index && textTrueAlign.unshift('')
|
||||
|
||||
this.textTrueAlign = textTrueAlign
|
||||
},
|
||||
getCurrentScrollData (init = false) {
|
||||
init && (this.currentIndex = 0)
|
||||
|
||||
const { currentIndex, rowTrueNum, allRowData, deepClone, carousel } = this
|
||||
|
||||
let dealAfterRowData = deepClone(allRowData).map(row => ({ ...row, fade: false }))
|
||||
|
||||
if (init && allRowData.length < rowTrueNum) {
|
||||
this.scrollData = dealAfterRowData
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const needNum = carousel === 'page' ? rowTrueNum * 2 : rowTrueNum + 1
|
||||
|
||||
const tempScrollData = dealAfterRowData.slice(currentIndex, currentIndex + needNum)
|
||||
|
||||
let stillNum = needNum - tempScrollData.length
|
||||
|
||||
while (stillNum) {
|
||||
tempScrollData.push(...deepClone(dealAfterRowData).slice(0, stillNum))
|
||||
|
||||
stillNum = needNum - tempScrollData.length
|
||||
}
|
||||
|
||||
this.scrollData = tempScrollData
|
||||
|
||||
const { doFade, waitTime, defaultWaitTime } = this
|
||||
|
||||
this.doFadeTimer = setTimeout(doFade, waitTime || defaultWaitTime)
|
||||
},
|
||||
doFade () {
|
||||
const { rowTrueNum, carousel, scrollData, allRowNum, currentIndex } = this
|
||||
|
||||
if (carousel === 'page') {
|
||||
scrollData.forEach((item, i) => i < rowTrueNum && (item.fade = true))
|
||||
|
||||
const tempIndex = currentIndex + rowTrueNum
|
||||
|
||||
const minus = tempIndex - allRowNum
|
||||
|
||||
this.currentIndex = minus >= 0 ? minus : tempIndex
|
||||
} else {
|
||||
scrollData[0].fade = true
|
||||
|
||||
this.currentIndex = currentIndex + 1 === allRowNum ? 0 : currentIndex + 1
|
||||
}
|
||||
|
||||
const { getCurrentScrollData } = this
|
||||
|
||||
this.reAnimationTimer = setTimeout(getCurrentScrollData, 1000)
|
||||
},
|
||||
emitClickEvent ({ data, index }, columnIndex) {
|
||||
this.$emit('click', { data, rowIndex: index, columnIndex: columnIndex + 1 })
|
||||
},
|
||||
stopAnimation () {
|
||||
const { reAnimationTimer, doFadeTimer } = this
|
||||
|
||||
reAnimationTimer && clearTimeout(reAnimationTimer)
|
||||
doFadeTimer && clearTimeout(doFadeTimer)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
},
|
||||
destroyed () {
|
||||
const { stopAnimation } = this
|
||||
|
||||
stopAnimation()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.scroll-board {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.title-container {
|
||||
height: 35px;
|
||||
font-size: 14px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.title-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&.left {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
&.right {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
&.center {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.row-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.row-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-shrink: 0;
|
||||
transition: all 0.5s;
|
||||
overflow: hidden;
|
||||
|
||||
&.fade {
|
||||
height: 0% !important;
|
||||
color: transparent;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.row-item-info {
|
||||
position: relative;
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
align-items: center;
|
||||
vertical-align:middle;
|
||||
font-size: 13px;
|
||||
|
||||
&.left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&.right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&.center {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.rii-width {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.index-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.index {
|
||||
font-size: 12px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,328 +0,0 @@
|
||||
<template>
|
||||
<div class="water-level-pond">
|
||||
<svg class="svg-container">
|
||||
<defs>
|
||||
<linearGradient :id="id" x1="0%" y1="100%" x2="0%" y2="0%">
|
||||
<stop v-for="lc in linearGradient" :key="lc[0]"
|
||||
:offset="lc[0]"
|
||||
:stop-color="lc[1]" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<text :stroke="`url(#${id})`"
|
||||
:fill="`url(#${id})`"
|
||||
:x="arcOriginPos[0] + 8"
|
||||
:y="arcOriginPos[1] + 8">
|
||||
{{ (level && Math.max(...level)) || 0 }}%
|
||||
</text>
|
||||
|
||||
<ellipse v-if="!type || type === 'circle'"
|
||||
:cx="arcOriginPos[0] + 8"
|
||||
:cy="arcOriginPos[1] + 8"
|
||||
:rx="canvasWH[0] / 2 + 5"
|
||||
:ry="canvasWH[1] / 2 + 5"
|
||||
:stroke="`url(#${id})`" />
|
||||
|
||||
<rect v-else
|
||||
x="2" y="2"
|
||||
:rx="type === 'roundRect' && 10" :ry="type === 'roundRect' && 10"
|
||||
:width="canvasWH[0] + 12"
|
||||
:height="canvasWH[1] + 12"
|
||||
:stroke="`url(#${id})`" />
|
||||
</svg>
|
||||
<canvas :ref="ref" :style="`border-radius: ${radius};`" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'WaterLevelPond',
|
||||
data () {
|
||||
return {
|
||||
ref: `water-level-pond-${(new Date()).getTime()}`,
|
||||
canvasDom: '',
|
||||
canvasWH: [0, 0],
|
||||
ctx: '',
|
||||
|
||||
id: `water-level-pond-${(new Date()).getTime()}`,
|
||||
|
||||
defaultColor: ['#00BAFF', '#3DE7C9'],
|
||||
|
||||
defaultWaveNum: 3,
|
||||
defaultWaveHeight: 0.2,
|
||||
defaultWaveOffset: -0.5,
|
||||
|
||||
waveAdded: 0.7,
|
||||
|
||||
arcOriginPos: [0, 0],
|
||||
drawColor: '',
|
||||
linearGradient: [],
|
||||
waveTrueNum: '',
|
||||
waveTrueHeight: '',
|
||||
waveTrueWidth: '',
|
||||
wavePoints: [],
|
||||
bottomPoints: [],
|
||||
overXPos: 0,
|
||||
currentPoints: [],
|
||||
animationHandler: ''
|
||||
}
|
||||
},
|
||||
props: ['level', 'type', 'colors', 'waveNum', 'waveHeight', 'borderColor', 'noGradient'],
|
||||
computed: {
|
||||
radius () {
|
||||
const { type } = this
|
||||
|
||||
if (type === 'circle') return '50%'
|
||||
|
||||
if (type === 'rect') return '0'
|
||||
|
||||
if (type === 'roundRect') return '10px'
|
||||
|
||||
return '50%'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const { $nextTick, initCanvas, calcOriginPos, level, draw } = this
|
||||
|
||||
$nextTick(e => {
|
||||
initCanvas()
|
||||
|
||||
calcOriginPos()
|
||||
|
||||
level && draw()
|
||||
})
|
||||
},
|
||||
initCanvas () {
|
||||
const { $refs, ref, labelRef, canvasWH } = this
|
||||
|
||||
const canvas = this.canvasDom = $refs[ref]
|
||||
|
||||
this.labelDom = $refs[labelRef]
|
||||
|
||||
canvasWH[0] = canvas.clientWidth
|
||||
canvasWH[1] = canvas.clientHeight
|
||||
|
||||
canvas.setAttribute('width', canvasWH[0])
|
||||
canvas.setAttribute('height', canvasWH[1])
|
||||
|
||||
this.ctx = canvas.getContext('2d')
|
||||
},
|
||||
calcOriginPos () {
|
||||
const { canvasWH, arcOriginPos } = this
|
||||
|
||||
arcOriginPos[0] = canvasWH[0] / 2
|
||||
arcOriginPos[1] = canvasWH[1] / 2
|
||||
},
|
||||
draw () {
|
||||
const { ctx, canvasWH } = this
|
||||
|
||||
ctx.clearRect(0, 0, ...canvasWH)
|
||||
|
||||
const { initColor, calcBorderLinearColor, calcWaveData } = this
|
||||
|
||||
initColor()
|
||||
|
||||
calcBorderLinearColor()
|
||||
|
||||
calcWaveData()
|
||||
|
||||
const { calcBottomPoints, calcOverXPos, drawWaveAnimation } = this
|
||||
|
||||
calcBottomPoints()
|
||||
|
||||
calcOverXPos()
|
||||
|
||||
drawWaveAnimation()
|
||||
},
|
||||
initColor () {
|
||||
const { colors, defaultColor } = this
|
||||
|
||||
this.drawColor = colors || defaultColor
|
||||
},
|
||||
calcBorderLinearColor () {
|
||||
const { colors, defaultColor, borderColor } = this
|
||||
|
||||
let trueColor = borderColor || colors || defaultColor
|
||||
|
||||
typeof trueColor === 'string' && (trueColor = [trueColor, trueColor])
|
||||
|
||||
const colorNum = trueColor.length
|
||||
|
||||
const colorOffsetGap = 100 / (colorNum - 1)
|
||||
|
||||
this.linearGradient = trueColor.map((c, i) => [colorOffsetGap * i, c])
|
||||
},
|
||||
calcWaveData () {
|
||||
const { waveNum, waveHeight, defaultWaveNum, defaultWaveHeight, canvasWH } = this
|
||||
|
||||
const waveTrueNum = this.waveTrueNum = waveNum || defaultWaveNum
|
||||
|
||||
const waveTrueHeight = this.waveTrueHeight = (waveHeight || defaultWaveHeight) * canvasWH[1]
|
||||
|
||||
const waveWidth = this.waveTrueWidth = canvasWH[0] / waveTrueNum
|
||||
|
||||
const { waveOffset, defaultWaveOffset, addWavePoint } = this
|
||||
|
||||
const waveOffsetLength = waveTrueHeight * (waveOffset || defaultWaveOffset)
|
||||
|
||||
const waveTop = waveTrueHeight + waveOffsetLength + canvasWH[1]
|
||||
|
||||
const waveBottom = waveOffsetLength + canvasWH[1]
|
||||
|
||||
const halfWidth = waveWidth / 2
|
||||
|
||||
this.wavePoints = new Array(waveTrueNum * 2 + 1).fill(0).map((t, i) =>
|
||||
[i * halfWidth, i % 2 === 0 ? waveBottom : waveTop])
|
||||
|
||||
addWavePoint() && addWavePoint() && addWavePoint()
|
||||
},
|
||||
addWavePoint () {
|
||||
const { wavePoints, waveTrueWidth } = this
|
||||
|
||||
const addPoint = [wavePoints[1][0] - waveTrueWidth, wavePoints[1][1]]
|
||||
|
||||
return wavePoints.unshift(addPoint)
|
||||
},
|
||||
calcBottomPoints () {
|
||||
const { canvasWH } = this
|
||||
|
||||
this.bottomPoints = [
|
||||
[...canvasWH],
|
||||
[0, canvasWH[1]]
|
||||
]
|
||||
},
|
||||
calcOverXPos () {
|
||||
const { canvasWH: [width], waveTrueWidth } = this
|
||||
|
||||
this.overXPos = width + waveTrueWidth
|
||||
},
|
||||
drawWaveAnimation () {
|
||||
const { ctx, canvasWH, drawWaveAnimation } = this
|
||||
|
||||
ctx.clearRect(0, 0, ...canvasWH)
|
||||
|
||||
const { getCurrentPoints, drawCurrentWave, calcNextFramePoints } = this
|
||||
|
||||
getCurrentPoints()
|
||||
|
||||
drawCurrentWave()
|
||||
|
||||
calcNextFramePoints()
|
||||
|
||||
this.animationHandler = requestAnimationFrame(drawWaveAnimation)
|
||||
},
|
||||
getCurrentPoints () {
|
||||
const { level, wavePoints, canvasWH: [, height] } = this
|
||||
|
||||
this.currentPoints = level.map(l =>
|
||||
wavePoints.map(([x, y]) =>
|
||||
[x, y - (l / 100 * height)]))
|
||||
},
|
||||
drawCurrentWave () {
|
||||
const { currentPoints, ctx, bottomPoints, drawColor, canvasWH: [, y], noGradient } = this
|
||||
|
||||
const { canvas: { drawSmoothlinePath, getLinearGradientColor } } = this
|
||||
|
||||
const { color: { hexToRgb } } = this
|
||||
|
||||
const multipleColor = typeof drawColor === 'object'
|
||||
|
||||
!multipleColor && (ctx.fillStyle = drawColor)
|
||||
|
||||
multipleColor &&
|
||||
!noGradient &&
|
||||
(ctx.fillStyle = getLinearGradientColor(ctx, [0, y], [0, 0], drawColor.map(c => hexToRgb(c, 0.5))))
|
||||
|
||||
const colorNum = drawColor.length
|
||||
|
||||
currentPoints.forEach((line, i) => {
|
||||
drawSmoothlinePath(ctx, line, false, true, true)
|
||||
|
||||
ctx.lineTo(...bottomPoints[0])
|
||||
ctx.lineTo(...bottomPoints[1])
|
||||
|
||||
ctx.closePath()
|
||||
|
||||
multipleColor && noGradient && (ctx.fillStyle = drawColor[i % colorNum])
|
||||
|
||||
ctx.fill()
|
||||
})
|
||||
},
|
||||
calcNextFramePoints () {
|
||||
const { wavePoints, waveAdded, addWavePoint, overXPos } = this
|
||||
|
||||
const addedWavePoints = wavePoints.map(([x, y]) => [x + waveAdded, y])
|
||||
|
||||
const lastPointIndex = addedWavePoints.length - 1
|
||||
|
||||
let addStatus = false
|
||||
|
||||
addedWavePoints[lastPointIndex][0] > overXPos &&
|
||||
addedWavePoints.pop() && (addStatus = true)
|
||||
|
||||
this.wavePoints = addedWavePoints
|
||||
|
||||
addStatus && addWavePoint()
|
||||
},
|
||||
stopAnimation () {
|
||||
const { animationHandler } = this
|
||||
|
||||
cancelAnimationFrame(animationHandler)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
},
|
||||
destroyed () {
|
||||
const { stopAnimation } = this
|
||||
|
||||
stopAnimation()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.water-level-pond {
|
||||
position: relative;
|
||||
|
||||
.percent-text {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
font-weight: bold;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.svg-container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
text {
|
||||
font-size: 25px;
|
||||
font-weight: bold;
|
||||
text-anchor: middle;
|
||||
dominant-baseline: middle;
|
||||
}
|
||||
|
||||
ellipse, rect {
|
||||
fill: none;
|
||||
stroke-width: 3;
|
||||
}
|
||||
|
||||
canvas {
|
||||
margin-top: 8px;
|
||||
margin-left: 8px;
|
||||
width: calc(~"100% - 16px");
|
||||
height: calc(~"100% - 16px");
|
||||
box-sizing: border-box;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,8 +0,0 @@
|
||||
export default [
|
||||
'#9cf4a7',
|
||||
'#66d7ee',
|
||||
'#eee966',
|
||||
'#a866ee',
|
||||
'#ee8f66',
|
||||
'#ee66aa'
|
||||
]
|
24
src/main.js
@ -1,24 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router/index'
|
||||
|
||||
import './assets/style/index.less'
|
||||
|
||||
import plugins from './plugins/index'
|
||||
|
||||
import auxiliary from './auxiliary/index'
|
||||
|
||||
import components from './components/index'
|
||||
|
||||
Vue.use(plugins)
|
||||
|
||||
Vue.use(auxiliary)
|
||||
|
||||
Vue.use(components)
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
@ -1,595 +0,0 @@
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
defaultAxisLineColor: '#666',
|
||||
defaultGridLineColor: '#666',
|
||||
defaultTagColor: '#666',
|
||||
|
||||
defaultGridLineType: 'line',
|
||||
defaultGridLineDash: [5, 5],
|
||||
|
||||
defaultXAxisOffset: 30,
|
||||
defaultAxisLineTagGap: 5,
|
||||
defaultAxisFontSize: 10,
|
||||
defaultAxisFontFamily: 'Arial',
|
||||
|
||||
valueMaxMin: [],
|
||||
agValueMaxMin: [],
|
||||
|
||||
valueAxisMaxMin: [],
|
||||
agValueAxisMaxMin: [],
|
||||
|
||||
valueAxisTag: [],
|
||||
agValueAxisTag: [],
|
||||
|
||||
labelAxisTag: [],
|
||||
agLabelAxisTag: [],
|
||||
|
||||
xAxisTagBA: ['', ''],
|
||||
agXAxisTagBA: ['', ''],
|
||||
yAxisTagBA: ['', ''],
|
||||
agYAxisTagBA: ['', ''],
|
||||
|
||||
addBAValueAxisTag: [],
|
||||
addBAAGValueAxisTag: [],
|
||||
|
||||
addBALabelAxisTag: [],
|
||||
addBAAGLabelAxisTag: [],
|
||||
|
||||
axisUnit: [],
|
||||
|
||||
axisFontSize: 0,
|
||||
axisFontFamily: '',
|
||||
|
||||
axisOffset: [],
|
||||
|
||||
axisOriginPos: [],
|
||||
axisWH: [],
|
||||
|
||||
axisAnglePos: {},
|
||||
|
||||
valueAxisTagPos: [],
|
||||
agValueAxisTagPos: [],
|
||||
|
||||
labelAxisTagPos: [],
|
||||
agLabelAxisTagPos: [],
|
||||
|
||||
tagAlign: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initAxis () {
|
||||
const { calcValuesMaxMin, calcValueAxisData, calcLabelAxisData } = this
|
||||
|
||||
calcValuesMaxMin()
|
||||
|
||||
calcValueAxisData()
|
||||
|
||||
calcLabelAxisData()
|
||||
|
||||
const { calcTagBA, calcAddBATag, calcAxisUnit } = this
|
||||
|
||||
calcTagBA()
|
||||
|
||||
calcAddBATag()
|
||||
|
||||
calcAxisUnit()
|
||||
|
||||
const { calcAxisFontData, calcAxisOffset, calcAxisAreaData } = this
|
||||
|
||||
calcAxisFontData()
|
||||
|
||||
calcAxisOffset()
|
||||
|
||||
calcAxisAreaData()
|
||||
|
||||
const { calcAxisAnglePos, calcValueAxisTagPos, calcLabelAxisTagPos } = this
|
||||
|
||||
calcAxisAnglePos()
|
||||
|
||||
calcValueAxisTagPos()
|
||||
|
||||
calcLabelAxisTagPos()
|
||||
|
||||
const { calcTagAlign } = this
|
||||
|
||||
calcTagAlign()
|
||||
},
|
||||
calcValuesMaxMin () {
|
||||
const { data: { data }, calcValueMaxMin } = this
|
||||
|
||||
const valueSeries = data.filter(({ againstAxis }) => !againstAxis)
|
||||
|
||||
if (valueSeries.length) this.valueMaxMin = calcValueMaxMin(valueSeries)
|
||||
|
||||
const agValueSeries = data.filter(({ againstAxis }) => againstAxis)
|
||||
|
||||
if (agValueSeries.length) this.agValueMaxMin = calcValueMaxMin(agValueSeries)
|
||||
},
|
||||
calcValueMaxMin (data) {
|
||||
const { mulValueAdd, calcMulValueAdd, getArrayMax, getArrayMin } = this
|
||||
|
||||
let valueSeries = data.map(({ data: td }) => td)
|
||||
|
||||
const min = getArrayMin(valueSeries)
|
||||
|
||||
mulValueAdd && (valueSeries = calcMulValueAdd(valueSeries))
|
||||
|
||||
const max = getArrayMax(valueSeries)
|
||||
|
||||
return [max, min]
|
||||
},
|
||||
calcMulValueAdd (values) {
|
||||
const { multipleSum, filterNull } = this
|
||||
|
||||
return values.map(series =>
|
||||
filterNull(series).map(n =>
|
||||
n instanceof Array ? multipleSum(...filterNull(n)) : n))
|
||||
},
|
||||
calcValueAxisData () {
|
||||
const { horizon, data: { x, ax, y, ay }, calcValueAxisTag } = this
|
||||
|
||||
const { valueMaxMin, agValueMaxMin, getValueAxisMaxMin } = this
|
||||
|
||||
const valueAxis = horizon ? [x, ax] : [y, ay]
|
||||
|
||||
if (valueMaxMin.length) {
|
||||
const valueAxisTag = this.valueAxisTag = calcValueAxisTag(valueMaxMin, valueAxis[0])
|
||||
|
||||
this.valueAxisMaxMin = getValueAxisMaxMin(valueAxisTag)
|
||||
}
|
||||
|
||||
if (agValueMaxMin.length) {
|
||||
const agValueAxisTag = this.agValueAxisTag = calcValueAxisTag(agValueMaxMin, valueAxis[1])
|
||||
|
||||
this.agValueAxisMaxMin = getValueAxisMaxMin(agValueAxisTag)
|
||||
}
|
||||
},
|
||||
calcValueAxisTag ([vmax, vmin], { max, min, num, fixed, data } = {}) {
|
||||
if (data) return data
|
||||
|
||||
let [trueMax, trueMin] = [max, min]
|
||||
|
||||
const thirdValueMinus = parseInt((vmax - vmin) / 3)
|
||||
|
||||
!max && (max !== 0) && (trueMax = vmax + thirdValueMinus)
|
||||
!min && (min !== 0) && (trueMin = vmin - thirdValueMinus)
|
||||
|
||||
const trueMinus = trueMax - trueMin
|
||||
|
||||
!num && trueMinus < 9 && (num = Math.ceil(trueMinus) + 1)
|
||||
!num && (num = 10)
|
||||
|
||||
const valueGap = trueMinus / (num - 1)
|
||||
|
||||
return Array(num).fill(0).map((t, i) =>
|
||||
(trueMin + i * valueGap).toFixed(fixed))
|
||||
},
|
||||
getValueAxisMaxMin (valueTag) {
|
||||
const lastIndex = valueTag.length - 1
|
||||
|
||||
return [
|
||||
parseFloat(valueTag[lastIndex]),
|
||||
parseFloat(valueTag[0])
|
||||
]
|
||||
},
|
||||
calcLabelAxisData () {
|
||||
const { horizon, data: { x, ax, y, ay } } = this
|
||||
|
||||
const labelAxis = horizon ? [y, ay] : [x, ax]
|
||||
|
||||
if (labelAxis[0] && labelAxis[0].data) this.labelAxisTag = labelAxis[0].data
|
||||
|
||||
if (labelAxis[1] && labelAxis[1].data) this.agLabelAxisTag = labelAxis[1].data
|
||||
},
|
||||
calcTagBA () {
|
||||
const { data: { x, ax, y, ay } } = this
|
||||
|
||||
if (x && x.tagBefore) this.xAxisTagBA[0] = x.tagBefore
|
||||
if (ax && ax.tagBefore) this.agXAxisTagBA[0] = ax.tagBefore
|
||||
if (y && y.tagBefore) this.yAxisTagBA[0] = y.tagBefore
|
||||
if (ay && ay.tagBefore) this.agYAxisTagBA[0] = ay.tagBefore
|
||||
|
||||
if (x && x.tagAfter) this.xAxisTagBA[1] = x.tagAfter
|
||||
if (ax && ax.tagAfter) this.agXAxisTagBA[1] = ax.tagAfter
|
||||
if (y && y.tagAfter) this.yAxisTagBA[1] = y.tagAfter
|
||||
if (ay && ay.tagAfter) this.agYAxisTagBA[1] = ay.tagAfter
|
||||
},
|
||||
calcAddBATag () {
|
||||
const { xAxisTagBA, agXAxisTagBA, yAxisTagBA, agYAxisTagBA } = this
|
||||
|
||||
const { valueAxisTag, agValueAxisTag, labelAxisTag, agLabelAxisTag } = this
|
||||
|
||||
const { horizon, addBATag } = this
|
||||
|
||||
const valueTagBA = horizon ? [xAxisTagBA, agXAxisTagBA] : [yAxisTagBA, agYAxisTagBA]
|
||||
|
||||
const labelTagBA = horizon ? [yAxisTagBA, agYAxisTagBA] : [xAxisTagBA, agXAxisTagBA]
|
||||
|
||||
if (valueAxisTag.length) this.addBAValueAxisTag = addBATag(valueAxisTag, valueTagBA[0])
|
||||
if (agValueAxisTag.length) this.addBAAGValueAxisTag = addBATag(agValueAxisTag, valueTagBA[1])
|
||||
if (labelAxisTag.length) this.addBALabelAxisTag = addBATag(labelAxisTag, labelTagBA[0])
|
||||
if (agLabelAxisTag.length) this.addBAAGLabelAxisTag = addBATag(agLabelAxisTag, labelTagBA[1])
|
||||
},
|
||||
addBATag (tags, ba) {
|
||||
return tags.map(tag => tag ? `${ba[0]}${tag}${ba[1]}` : tag)
|
||||
},
|
||||
calcAxisUnit () {
|
||||
const { data: { x, ax, y, ay } } = this
|
||||
|
||||
if (x && x.unit) this.axisUnit[0] = x.unit
|
||||
if (ax && ax.unit) this.axisUnit[1] = ax.unit
|
||||
if (y && y.unit) this.axisUnit[2] = y.unit
|
||||
if (ay && ay.unit) this.axisUnit[3] = ay.unit
|
||||
},
|
||||
calcAxisFontData () {
|
||||
const { defaultAxisFontSize, defaultAxisFontFamily } = this
|
||||
|
||||
const { data: { axisFontSize, axisFontFamily } } = this
|
||||
|
||||
this.axisFontSize = axisFontSize || defaultAxisFontSize
|
||||
|
||||
this.axisFontFamily = axisFontFamily || defaultAxisFontFamily
|
||||
},
|
||||
calcAxisOffset () {
|
||||
const { horizon, axisUnit, defaultXAxisOffset } = this
|
||||
|
||||
const { addBAValueAxisTag, addBAAGValueAxisTag, addBALabelAxisTag, addBAAGLabelAxisTag } = this
|
||||
|
||||
const { axisFontSize, axisFontFamily, defaultAxisLineTagGap } = this
|
||||
|
||||
const { data: { x, ax, y, ay } } = this
|
||||
|
||||
const { ctx, canvas: { getTextsWidth }, boundaryGap } = this
|
||||
|
||||
ctx.font = `${axisFontSize}px ${axisFontFamily}`
|
||||
|
||||
this.axisOffset[0] = (ax && ax.offset) || defaultXAxisOffset
|
||||
this.axisOffset[2] = (x && x.offset) || defaultXAxisOffset
|
||||
|
||||
const horizonAxisTags = horizon
|
||||
? [addBALabelAxisTag, addBAAGLabelAxisTag]
|
||||
: [addBAValueAxisTag, addBAAGValueAxisTag]
|
||||
|
||||
this.axisOffset[3] = (y && y.offset) ||
|
||||
Math.max(...getTextsWidth(ctx, [axisUnit[2] || '']),
|
||||
...getTextsWidth(ctx, horizonAxisTags[0].length ? horizonAxisTags[0] : 0)) + defaultAxisLineTagGap
|
||||
|
||||
// axis offset 1
|
||||
const xAxisTags = horizon ? addBAValueAxisTag : addBALabelAxisTag
|
||||
|
||||
let xAxisTagsHalfWidth = 0
|
||||
|
||||
xAxisTags.length && (xAxisTagsHalfWidth = ctx.measureText(xAxisTags.length - 1).width / 2)
|
||||
|
||||
let rightOffset = Math.max(...getTextsWidth(ctx, [axisUnit[3] || '']),
|
||||
...getTextsWidth(ctx, [axisUnit[0] || '']),
|
||||
...getTextsWidth(ctx, horizonAxisTags[1].length ? horizonAxisTags[1] : [''])) + defaultAxisLineTagGap
|
||||
|
||||
;(!boundaryGap || horizon) && (rightOffset += (xAxisTagsHalfWidth + 5))
|
||||
|
||||
this.axisOffset[1] = (ay && ay.offset) || rightOffset
|
||||
|
||||
if (y && y.noTag) this.axisOffset[3] = 1
|
||||
if (ay && ay.noTag) this.axisOffset[1] = 1
|
||||
},
|
||||
calcAxisAreaData () {
|
||||
const { canvasWH, axisOffset, axisWH, axisOriginPos } = this
|
||||
|
||||
axisWH[0] = canvasWH[0] - axisOffset[1] - axisOffset[3]
|
||||
axisWH[1] = canvasWH[1] - axisOffset[0] - axisOffset[2]
|
||||
|
||||
axisOriginPos[0] = axisOffset[3]
|
||||
axisOriginPos[1] = axisWH[1] + axisOffset[0]
|
||||
},
|
||||
calcAxisAnglePos () {
|
||||
const { axisWH, axisOriginPos, axisAnglePos } = this
|
||||
|
||||
axisAnglePos.leftTop = [axisOriginPos[0], axisOriginPos[1] - axisWH[1]]
|
||||
axisAnglePos.rightTop = [axisOriginPos[0] + axisWH[0], axisOriginPos[1] - axisWH[1]]
|
||||
|
||||
axisAnglePos.leftBottom = axisOriginPos
|
||||
axisAnglePos.rightBottom = [axisOriginPos[0] + axisWH[0], axisOriginPos[1]]
|
||||
},
|
||||
calcValueAxisTagPos () {
|
||||
const { horizon, axisOriginPos, axisAnglePos } = this
|
||||
|
||||
const { valueAxisTag, agValueAxisTag, getValueAxisTagPos } = this
|
||||
|
||||
if (valueAxisTag) this.valueAxisTagPos = getValueAxisTagPos(valueAxisTag, axisOriginPos)
|
||||
|
||||
const basePoint = horizon ? axisAnglePos.leftTop : axisAnglePos.rightBottom
|
||||
|
||||
if (agValueAxisTag) this.agValueAxisTagPos = getValueAxisTagPos(agValueAxisTag, basePoint)
|
||||
},
|
||||
getValueAxisTagPos (tags, [x, y]) {
|
||||
const { horizon, axisWH } = this
|
||||
|
||||
const tagsNum = tags.length
|
||||
|
||||
const areaLength = horizon ? axisWH[0] : axisWH[1]
|
||||
|
||||
const tagGap = areaLength / (tagsNum - 1)
|
||||
|
||||
return new Array(tagsNum).fill(0).map((t, i) =>
|
||||
horizon ? [x + tagGap * i, y] : [x, y - tagGap * i])
|
||||
},
|
||||
calcLabelAxisTagPos () {
|
||||
const { horizon, getLabelAxisTagPos, axisAnglePos } = this
|
||||
|
||||
const { labelAxisTag, agLabelAxisTag, axisOriginPos } = this
|
||||
|
||||
if (labelAxisTag.length) this.labelAxisTagPos = getLabelAxisTagPos(labelAxisTag, axisOriginPos)
|
||||
|
||||
const basePoint = horizon ? axisAnglePos.rightBottom : axisAnglePos.leftTop
|
||||
|
||||
if (agLabelAxisTag.length) this.agLabelAxisTagPos = getLabelAxisTagPos(agLabelAxisTag, basePoint)
|
||||
},
|
||||
getLabelAxisTagPos (tags, [x, y]) {
|
||||
const { horizon, axisWH, boundaryGap } = this
|
||||
|
||||
const tagsNum = tags.length
|
||||
|
||||
const areaLength = horizon ? axisWH[1] : axisWH[0]
|
||||
|
||||
let gapColumnNum = boundaryGap ? tagsNum : tagsNum - 1
|
||||
|
||||
gapColumnNum === 0 && (gapColumnNum = 1)
|
||||
|
||||
const tagGap = areaLength / gapColumnNum
|
||||
|
||||
const halfGap = tagGap / 2
|
||||
|
||||
const tempPos = new Array(tagsNum).fill(0)
|
||||
|
||||
if (boundaryGap) {
|
||||
return tempPos.map((t, i) =>
|
||||
horizon ? [x, y - (tagGap * i) - halfGap] : [x + (tagGap * i) + halfGap, y])
|
||||
}
|
||||
|
||||
if (!boundaryGap) {
|
||||
return tempPos.map((t, i) =>
|
||||
horizon ? [x, y + tagGap * i] : [x + tagGap * i, y])
|
||||
}
|
||||
},
|
||||
calcTagAlign () {
|
||||
const { tagAlign } = this
|
||||
|
||||
tagAlign.x = ['center', 'top']
|
||||
tagAlign.y = ['right', 'middle']
|
||||
tagAlign.ax = ['center', 'bottom']
|
||||
tagAlign.ay = ['left', 'middle']
|
||||
},
|
||||
drawAxis () {
|
||||
const { drawAxisLine, drawAxisTag, drawAxisUnit } = this
|
||||
|
||||
drawAxisLine()
|
||||
|
||||
drawAxisTag()
|
||||
|
||||
drawAxisUnit()
|
||||
|
||||
const { drawAxisGrid } = this
|
||||
|
||||
drawAxisGrid()
|
||||
},
|
||||
drawAxisLine () {
|
||||
const { ctx, horizon, axisOriginPos, axisAnglePos } = this
|
||||
|
||||
const { defaultAxisLineColor, agValueAxisTag, agLabelAxisTag } = this
|
||||
|
||||
const { data: { x, ax, y, ay } } = this
|
||||
|
||||
ctx.lineWidth = 1
|
||||
|
||||
if (!x || !x.noAxisLine) {
|
||||
ctx.strokeStyle = (x && x.axisLineColor) || defaultAxisLineColor
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(...axisOriginPos)
|
||||
ctx.lineTo(...axisAnglePos.rightBottom)
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
if (!y || !y.noAxisLine) {
|
||||
ctx.strokeStyle = (y && y.axisLineColor) || defaultAxisLineColor
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(...axisOriginPos)
|
||||
ctx.lineTo(...axisAnglePos.leftTop)
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
const agValueAxis = horizon ? ay : ax
|
||||
|
||||
if (agValueAxisTag.length && (!agValueAxis || !agValueAxis.noAxisLine)) {
|
||||
ctx.strokeStyle = (agValueAxis && agValueAxis.axisLineColor) || defaultAxisLineColor
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(...(horizon ? axisAnglePos.leftTop : axisAnglePos.rightTop))
|
||||
ctx.lineTo(...(horizon ? axisAnglePos.rightTop : axisAnglePos.rightBottom))
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
const agLebalAxis = horizon ? ax : ay
|
||||
|
||||
if (agLabelAxisTag.length && (!agLebalAxis || !agLebalAxis.noAxisLine)) {
|
||||
ctx.strokeStyle = (agLebalAxis && agLebalAxis.axisLineColor) || defaultAxisLineColor
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(...(horizon ? axisAnglePos.rightTop : axisAnglePos.leftTop))
|
||||
ctx.lineTo(...(horizon ? axisAnglePos.rightBottom : axisAnglePos.rightTop))
|
||||
ctx.stroke()
|
||||
}
|
||||
},
|
||||
drawAxisTag () {
|
||||
const { horizon, tagAlign, defaultAxisLineTagGap: offset } = this
|
||||
|
||||
const { data: { x, ax, y, ay }, drawAxisSeriesTag } = this
|
||||
|
||||
const xAxis = horizon ? ['addBAValueAxisTag', 'valueAxisTagPos'] : ['addBALabelAxisTag', 'labelAxisTagPos']
|
||||
const yAxis = horizon ? ['addBALabelAxisTag', 'labelAxisTagPos'] : ['addBAValueAxisTag', 'valueAxisTagPos']
|
||||
const agXAxis = horizon ? ['addBAAGValueAxisTag', 'agValueAxisTagPos'] : ['addBAAGLabelAxisTag', 'agLabelAxisTagPos']
|
||||
const agYAxis = horizon ? ['addBAAGLabelAxisTag', 'agLabelAxisTagPos'] : ['addBAAGValueAxisTag', 'agValueAxisTagPos']
|
||||
|
||||
if (!x || !x.noAxisTag) drawAxisSeriesTag(...xAxis.map(td => this[td]), x, tagAlign.x, [0, offset], x && x.rotate)
|
||||
if (!y || !y.noAxisTag) drawAxisSeriesTag(...yAxis.map(td => this[td]), y, tagAlign.y, [-offset, 0])
|
||||
if (!ax || !ax.noAxisTag) drawAxisSeriesTag(...agXAxis.map(td => this[td]), ax, tagAlign.ax, [0, -offset])
|
||||
if (!ay || !ay.noAxisTag) drawAxisSeriesTag(...agYAxis.map(td => this[td]), ay, tagAlign.ay, [offset, 0])
|
||||
},
|
||||
drawAxisSeriesTag (tags, tagPos, { fontSize, fontFamily, tagColor } = {}, align, offset, rotate = false) {
|
||||
const { ctx, defaultAxisFontSize, defaultAxisFontFamily, defaultTagColor, drawColors } = this
|
||||
|
||||
let color = tagColor || defaultTagColor
|
||||
|
||||
color === 'colors' && (color = drawColors)
|
||||
|
||||
const colorNum = color.length
|
||||
|
||||
const mulColor = color instanceof Array
|
||||
|
||||
ctx.font = `${fontSize || defaultAxisFontSize}px ${fontFamily || defaultAxisFontFamily}`
|
||||
|
||||
!mulColor && (ctx.fillStyle = color)
|
||||
|
||||
ctx.textAlign = align[0]
|
||||
ctx.textBaseline = align[1]
|
||||
|
||||
tags.forEach((tag, i) => {
|
||||
if (!tag && tag !== 0) return
|
||||
|
||||
const currentPos = [tagPos[i][0] + offset[0], tagPos[i][1] + offset[1]]
|
||||
|
||||
mulColor && (ctx.fillStyle = color[i % colorNum])
|
||||
|
||||
if (rotate) {
|
||||
ctx.textAlign = 'left'
|
||||
ctx.textBaseline = 'top'
|
||||
|
||||
ctx.save()
|
||||
ctx.translate(...currentPos)
|
||||
ctx.rotate(rotate * Math.PI / 180)
|
||||
}
|
||||
|
||||
ctx.fillText(tag, ...(rotate ? [0, 0] : currentPos))
|
||||
|
||||
if (rotate) ctx.restore()
|
||||
})
|
||||
},
|
||||
drawAxisUnit () {
|
||||
const { axisOriginPos, canvasWH, drawUnit, defaultAxisLineTagGap } = this
|
||||
|
||||
const { data: { x, ax, y, ay }, axisAnglePos } = this
|
||||
|
||||
if (x) {
|
||||
const pos = [canvasWH[0], axisOriginPos[1] + defaultAxisLineTagGap]
|
||||
drawUnit(x, pos, ['right', 'top'])
|
||||
}
|
||||
|
||||
if (ax) {
|
||||
const pos = [canvasWH[0], axisAnglePos.rightTop[1] - defaultAxisLineTagGap]
|
||||
drawUnit(ax, pos, ['right', 'bottom'])
|
||||
}
|
||||
|
||||
if (y) {
|
||||
const pos = [axisOriginPos[0] - defaultAxisLineTagGap, 0]
|
||||
drawUnit(y, pos, ['right', 'top'])
|
||||
}
|
||||
|
||||
if (ay) {
|
||||
const pos = [axisAnglePos.rightTop[0] + defaultAxisLineTagGap, 0]
|
||||
drawUnit(ay, pos, ['left', 'top'])
|
||||
}
|
||||
},
|
||||
drawUnit ({ unit, unitColor, fontSize, fontFamily }, pos, align) {
|
||||
const { defaultTagColor, defaultAxisFontSize, defaultAxisFontFamily } = this
|
||||
|
||||
const { ctx } = this
|
||||
|
||||
if (!unit) return
|
||||
|
||||
ctx.font = `${fontSize || defaultAxisFontSize}px ${fontFamily || defaultAxisFontFamily}`
|
||||
|
||||
ctx.fillStyle = unitColor || defaultTagColor
|
||||
|
||||
ctx.textAlign = align[0]
|
||||
ctx.textBaseline = align[1]
|
||||
|
||||
ctx.fillText(unit, ...pos)
|
||||
},
|
||||
drawAxisGrid () {
|
||||
const { valueAxisTagPos, agValueAxisTagPos, labelAxisTagPos, agLabelAxisTagPos } = this
|
||||
|
||||
const { valueAxisTag, agValueAxisTag, labelAxisTag, agLabelAxisTag } = this
|
||||
|
||||
const { data: { x, ax, y, ay }, horizon, drawGrid, boundaryGap } = this
|
||||
|
||||
const xAxis = horizon ? [valueAxisTag, valueAxisTagPos] : [labelAxisTag, labelAxisTagPos]
|
||||
|
||||
let xLLLineStatus = [false, false]
|
||||
|
||||
if (horizon) {
|
||||
xLLLineStatus = [true, false]
|
||||
} else {
|
||||
xLLLineStatus = boundaryGap ? [false, false] : [true, true]
|
||||
}
|
||||
|
||||
if (xAxis[0].length) drawGrid(x, ...xAxis, false, false, true, ...xLLLineStatus)
|
||||
|
||||
const yAxis = horizon ? [labelAxisTag, labelAxisTagPos] : [valueAxisTag, valueAxisTagPos]
|
||||
|
||||
if (yAxis[0].length) drawGrid(y, ...yAxis, true, true, false, !horizon)
|
||||
|
||||
const agXAxis = horizon ? [agValueAxisTag, agValueAxisTagPos] : [agLabelAxisTag, agLabelAxisTagPos]
|
||||
|
||||
if (agXAxis[0].length) drawGrid(ax, ...agXAxis, false, false, false, ...(boundaryGap ? [false, false] : [true, true]))
|
||||
|
||||
const agYAxis = horizon ? [agLabelAxisTag, agLabelAxisTagPos] : [agValueAxisTag, agValueAxisTagPos]
|
||||
|
||||
if (agYAxis[0].length) drawGrid(ay, ...agYAxis, true, false, false, true)
|
||||
},
|
||||
drawGrid (axis = {}, gridTag, gridPos, horizon = true, right = true, top = true, noFirst = false, noLast = false) {
|
||||
const { grid, gridLineColor, gridLineType, gridLineDash } = axis
|
||||
|
||||
if (!grid) return
|
||||
|
||||
const { defaultGridLineType, defaultGridLineColor, defaultGridLineDash } = this
|
||||
|
||||
const { ctx, drawColors, axisWH } = this
|
||||
|
||||
const trueGridLineType = gridLineType || defaultGridLineType
|
||||
const trueGridLineDash = trueGridLineType === 'dashed' ? (gridLineDash || defaultGridLineDash) : [10, 0]
|
||||
|
||||
ctx.setLineDash(trueGridLineDash)
|
||||
|
||||
let color = gridLineColor || defaultGridLineColor
|
||||
|
||||
color === 'colors' && (color = drawColors)
|
||||
|
||||
const mulColor = color instanceof Array
|
||||
|
||||
const colorNum = color.length
|
||||
|
||||
!mulColor && (ctx.strokeStyle = color)
|
||||
|
||||
ctx.lineWidth = 1
|
||||
|
||||
const gridLastIndex = gridPos.length - 1
|
||||
|
||||
gridPos.forEach((pos, i) => {
|
||||
if (!gridTag[i] && gridTag[i] !== 0) return
|
||||
|
||||
if (i === 0 && noFirst) return
|
||||
|
||||
if (i === gridLastIndex && noLast) return
|
||||
|
||||
ctx.beginPath()
|
||||
|
||||
mulColor && (ctx.strokeStyle = color[i % colorNum])
|
||||
|
||||
ctx.moveTo(...pos)
|
||||
ctx.lineTo(...(horizon
|
||||
? [right ? pos[0] + axisWH[0] : pos[0] - axisWH[0], pos[1]]
|
||||
: [pos[0], top ? pos[1] - axisWH[1] : pos[1] + axisWH[1]]))
|
||||
|
||||
ctx.stroke()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
canvasDom: '',
|
||||
canvasWH: [0, 0],
|
||||
ctx: '',
|
||||
centerPos: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initCanvas () {
|
||||
const { $nextTick } = this
|
||||
|
||||
return new Promise(resolve => {
|
||||
$nextTick(e => {
|
||||
const { $refs, ref, labelRef, canvasWH, centerPos } = this
|
||||
|
||||
const canvas = this.canvasDom = $refs[ref]
|
||||
|
||||
this.labelDom = $refs[labelRef]
|
||||
|
||||
canvasWH[0] = canvas.clientWidth
|
||||
canvasWH[1] = canvas.clientHeight
|
||||
|
||||
canvas.setAttribute('width', canvasWH[0])
|
||||
canvas.setAttribute('height', canvasWH[1])
|
||||
|
||||
this.ctx = canvas.getContext('2d')
|
||||
|
||||
centerPos[0] = canvasWH[0] / 2
|
||||
centerPos[1] = canvasWH[1] / 2
|
||||
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
},
|
||||
clearCanvas () {
|
||||
const { ctx, canvasWH } = this
|
||||
|
||||
ctx.clearRect(0, 0, ...canvasWH)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
import defaultColors from '../config/color.js'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
defaultColors,
|
||||
|
||||
drawColors: '',
|
||||
|
||||
drawColorsMul: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initColors () {
|
||||
const { colors, defaultColors } = this
|
||||
|
||||
const trueDrawColors = this.drawColors = colors || defaultColors
|
||||
|
||||
this.drawColorsMul = trueDrawColors instanceof Array
|
||||
}
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
import Axios from 'axios'
|
||||
|
||||
const timeout = 3000
|
||||
|
||||
Axios.defaults.timeout = timeout
|
||||
|
||||
function interception (fn, methods) {
|
||||
return (...args) => {
|
||||
// Request params num
|
||||
const argsLen = args.length
|
||||
|
||||
// GET Request
|
||||
if (methods === 'get' && argsLen > 1) {
|
||||
const requerParams = Object.entries(args[1]).map(([key, value]) => {
|
||||
return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
|
||||
}).join('&')
|
||||
|
||||
args[0] += `?${requerParams}`
|
||||
|
||||
args.pop()
|
||||
|
||||
// POST Request
|
||||
} else if (methods === 'post' && argsLen > 2) {
|
||||
args[1] = Object.entries(args[1]).map(([key, value]) => `${key}=${value}`).join('&')
|
||||
|
||||
args.pop()
|
||||
}
|
||||
|
||||
return fn.apply(this, args)
|
||||
.then(res => {
|
||||
let { respCode, respMessage, serverDate, respBody, respList } = res.data
|
||||
/**
|
||||
* respCode:
|
||||
* success 成功
|
||||
* error 失败
|
||||
* warning 警告
|
||||
* fatalError 系统错误
|
||||
* session_timeout 会话超时或无效
|
||||
*/
|
||||
let temp = {
|
||||
code: respCode,
|
||||
msg: respMessage,
|
||||
timestamp: serverDate,
|
||||
data: {}
|
||||
}
|
||||
// 返回数据为list
|
||||
if (respList) {
|
||||
let data = {
|
||||
list: respList,
|
||||
pageIndex: res.data.pageIndex,
|
||||
pageSize: res.data.pageSize,
|
||||
pageCount: res.data.pages,
|
||||
total: res.data.recCount
|
||||
}
|
||||
temp.data = data
|
||||
// 开发对接接口过程中的辅助字段说明
|
||||
if (res.data.zhConsult) {
|
||||
temp.remarks = res.data.zhConsult
|
||||
}
|
||||
} else {
|
||||
temp.data = { ...respBody }
|
||||
}
|
||||
return temp
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default function (Vue) {
|
||||
Vue.prototype.$http = Axios
|
||||
|
||||
Vue.prototype.$http.get = interception(Vue.prototype.$http.get, 'get')
|
||||
Vue.prototype.$http.post = interception(Vue.prototype.$http.post, 'post')
|
||||
}
|
@ -1,195 +0,0 @@
|
||||
import { filterNull } from './methodsExtend'
|
||||
|
||||
export function drawLine (ctx, lineBegin, lineEnd, lineWidth = 2, lineColor = '#000', dashArray = [10, 0]) {
|
||||
if (!ctx || !lineBegin || !lineEnd) return
|
||||
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.moveTo(...lineBegin)
|
||||
ctx.lineTo(...lineEnd)
|
||||
|
||||
ctx.closePath()
|
||||
|
||||
ctx.lineWidth = lineWidth
|
||||
ctx.strokeStyle = lineColor
|
||||
ctx.setLineDash(dashArray)
|
||||
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
export function drawPolylinePath (ctx, points, close = false, newPath = false) {
|
||||
if (!ctx || !points.length) return
|
||||
|
||||
newPath && ctx.beginPath()
|
||||
|
||||
points.forEach((point, i) =>
|
||||
point && (i === 0 ? ctx.moveTo(...point) : ctx.lineTo(...point)))
|
||||
|
||||
close && ctx.lineTo(...points[0])
|
||||
}
|
||||
|
||||
export function drawPolyline (ctx, points, lineWidth = 2, lineColor = '#000', close = false, dashArray = [10, 0], newPath = false) {
|
||||
if (!ctx || !points.length) return
|
||||
|
||||
drawPolylinePath(ctx, points, close, newPath)
|
||||
|
||||
ctx.lineWidth = lineWidth
|
||||
ctx.strokeStyle = lineColor
|
||||
ctx.setLineDash(dashArray)
|
||||
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
export function drawSmoothlinePath (ctx, points, close = false, newPath = false, moveTo = false) {
|
||||
const canDrawPoints = filterNull(points)
|
||||
|
||||
if (!ctx || canDrawPoints.length < 2) return
|
||||
|
||||
close && canDrawPoints.push(canDrawPoints[0])
|
||||
|
||||
newPath && ctx.beginPath()
|
||||
|
||||
if (canDrawPoints.length === 2) {
|
||||
ctx.moveTo(...canDrawPoints[0])
|
||||
ctx.lineTo(...canDrawPoints[1])
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const lastPointIndex = canDrawPoints.length - 1
|
||||
|
||||
moveTo && ctx.moveTo(...canDrawPoints[0])
|
||||
|
||||
canDrawPoints.forEach((t, i) =>
|
||||
(i !== lastPointIndex) && drawBezierCurveLinePath(ctx,
|
||||
...getBezierCurveLineControlPoints(canDrawPoints, i, false),
|
||||
canDrawPoints[i + 1]))
|
||||
}
|
||||
|
||||
export function getBezierCurveLineControlPoints (points, index, close = false, offsetA = 0.25, offsetB = 0.25) {
|
||||
const pointNum = points.length
|
||||
|
||||
if (pointNum < 3 || index >= pointNum) return
|
||||
|
||||
let beforePointIndex = index - 1
|
||||
beforePointIndex < 0 && (beforePointIndex = (close ? pointNum + beforePointIndex : 0))
|
||||
|
||||
let afterPointIndex = index + 1
|
||||
afterPointIndex >= pointNum && (afterPointIndex = (close ? afterPointIndex - pointNum : pointNum - 1))
|
||||
|
||||
let afterNextPointIndex = index + 2
|
||||
afterNextPointIndex >= pointNum && (afterNextPointIndex = (close ? afterNextPointIndex - pointNum : pointNum - 1))
|
||||
|
||||
const pointBefore = points[beforePointIndex]
|
||||
const pointMiddle = points[index]
|
||||
const pointAfter = points[afterPointIndex]
|
||||
const pointAfterNext = points[afterNextPointIndex]
|
||||
|
||||
return [
|
||||
[
|
||||
pointMiddle[0] + offsetA * (pointAfter[0] - pointBefore[0]),
|
||||
pointMiddle[1] + offsetA * (pointAfter[1] - pointBefore[1])
|
||||
],
|
||||
[
|
||||
pointAfter[0] - offsetB * (pointAfterNext[0] - pointMiddle[0]),
|
||||
pointAfter[1] - offsetB * (pointAfterNext[1] - pointMiddle[1])
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
export function drawSmoothline (ctx, points, lineWidth = 2, lineColor = '#000', close = false, dashArray = [10, 0], newPath = false, moveTo = false) {
|
||||
if (!ctx || points.length < 3) return
|
||||
|
||||
drawSmoothlinePath(ctx, points, close, newPath, moveTo)
|
||||
|
||||
ctx.lineWidth = lineWidth
|
||||
ctx.strokeStyle = lineColor
|
||||
ctx.setLineDash(dashArray)
|
||||
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
export function drawBezierCurveLinePath (ctx, ctlBefore, ctlAfter, end, newPath = false) {
|
||||
if (!ctx || !ctlBefore || !ctlAfter || !end) return
|
||||
|
||||
newPath && ctx.beginPath()
|
||||
|
||||
ctx.bezierCurveTo(...ctlBefore, ...ctlAfter, ...end)
|
||||
}
|
||||
|
||||
export function drawPoints (ctx, points, radius = 10, color = '#000') {
|
||||
points.forEach(point => {
|
||||
if (!point) return
|
||||
|
||||
ctx.beginPath()
|
||||
|
||||
ctx.arc(...point, radius, 0, Math.PI * 2)
|
||||
|
||||
ctx.fillStyle = color
|
||||
|
||||
ctx.fill()
|
||||
})
|
||||
}
|
||||
|
||||
export function getLinearGradientColor (ctx, begin, end, color) {
|
||||
if (!ctx || !begin || !end || !color.length) return
|
||||
|
||||
let colors = color
|
||||
|
||||
typeof colors === 'string' && (colors = [color, color])
|
||||
|
||||
const linearGradientColor = ctx.createLinearGradient(...begin, ...end)
|
||||
|
||||
const colorGap = 1 / (colors.length - 1)
|
||||
|
||||
colors.forEach((c, i) => linearGradientColor.addColorStop(colorGap * i, c))
|
||||
|
||||
return linearGradientColor
|
||||
}
|
||||
|
||||
export function getRadialGradientColor (ctx, origin, begin = 0, end = 100, color) {
|
||||
if (!ctx || !origin || !color.length) return
|
||||
|
||||
let colors = color
|
||||
|
||||
typeof colors === 'string' && (colors = [color, color])
|
||||
|
||||
const radialGradientColor = ctx.createRadialGradient(...origin, begin, ...origin, end)
|
||||
|
||||
const colorGap = 1 / (colors.length - 1)
|
||||
|
||||
colors.forEach((c, i) => radialGradientColor.addColorStop(colorGap * i, c))
|
||||
|
||||
return radialGradientColor
|
||||
}
|
||||
|
||||
export function getCircleRadianPoint (x, y, radius, radian) {
|
||||
const { sin, cos } = Math
|
||||
|
||||
return [x + cos(radian) * radius, y + sin(radian) * radius]
|
||||
}
|
||||
|
||||
export function getTextsWidth (ctx, texts) {
|
||||
if (!ctx || !texts) return
|
||||
|
||||
return texts.map(text => ctx.measureText(text).width)
|
||||
}
|
||||
|
||||
const canvas = {
|
||||
drawLine,
|
||||
drawPolylinePath,
|
||||
drawPolyline,
|
||||
getBezierCurveLineControlPoints,
|
||||
drawSmoothlinePath,
|
||||
drawSmoothline,
|
||||
drawBezierCurveLinePath,
|
||||
drawPoints,
|
||||
getLinearGradientColor,
|
||||
getRadialGradientColor,
|
||||
getCircleRadianPoint,
|
||||
getTextsWidth
|
||||
}
|
||||
|
||||
export default function (Vue) {
|
||||
Vue.prototype.canvas = canvas
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
const hexReg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
|
||||
const rgbReg = /^(rgb|rgba|RGB|RGBA)/
|
||||
|
||||
/**
|
||||
* @description hex color to rgb / rgba color
|
||||
* @param {string} rgba opacity
|
||||
* @return {string} rgb / rgba color
|
||||
*/
|
||||
export function hexToRgb (hex, opacity) {
|
||||
if (!hex || !hexReg.test(hex)) return false
|
||||
|
||||
hex = hex.toLowerCase().replace('#', '')
|
||||
|
||||
// deal 3bit hex color to 6bit hex color
|
||||
hex.length === 3 && (hex = Array.from(hex).map(hexNum => hexNum + hexNum).join())
|
||||
|
||||
let rgb = []
|
||||
|
||||
for (let i = 0; i < 6; i += 2) {
|
||||
rgb.push(parseInt(`0x${hex.slice(i, i + 2)}`))
|
||||
}
|
||||
|
||||
rgb = rgb.join(',')
|
||||
|
||||
if (opacity) {
|
||||
return `rgba(${rgb}, ${opacity})`
|
||||
} else {
|
||||
return `rgb(${rgb})`
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description rgb / rgba color to hex color
|
||||
* @return {string} hex color
|
||||
*/
|
||||
export function rgbToHex (rgb) {
|
||||
if (!rgb || !rgbReg.test(rgb)) return false
|
||||
|
||||
rgb = rgb.toLowerCase().replace(/rgb\(|rgba\(|\)/g, '').split(',').slice(0, 3)
|
||||
|
||||
const hex = rgb.map((rgbNum) => Number(rgbNum).toString(16)).map((rgbNum) => rgbNum === '0' ? rgbNum + rgbNum : rgbNum).join('')
|
||||
|
||||
return `#${hex}`
|
||||
}
|
||||
|
||||
const color = {
|
||||
hexToRgb,
|
||||
rgbToHex
|
||||
}
|
||||
|
||||
export default function (Vue) {
|
||||
Vue.prototype.color = color
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import methodsExtend from './methodsExtend'
|
||||
|
||||
import canvasExtend from './canvasExtend'
|
||||
|
||||
import colorExtend from './colorExtend'
|
||||
|
||||
import axiosExtend from './axiosExtend'
|
||||
|
||||
export default function (Vue) {
|
||||
methodsExtend(Vue)
|
||||
canvasExtend(Vue)
|
||||
colorExtend(Vue)
|
||||
axiosExtend(Vue)
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
const { parse, stringify } = JSON
|
||||
|
||||
export function deepClone (object) {
|
||||
return parse(stringify(object))
|
||||
}
|
||||
|
||||
export function deleteArrayAllItems (arrays) {
|
||||
arrays.forEach(element => element.splice(0, element.length))
|
||||
}
|
||||
|
||||
export function debounce (delay, callback) {
|
||||
let lastTime
|
||||
|
||||
return function () {
|
||||
clearTimeout(lastTime)
|
||||
|
||||
const [that, args] = [this, arguments]
|
||||
|
||||
lastTime = setTimeout(() => {
|
||||
callback.apply(that, args)
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
|
||||
export function randomExtend (minNum, maxNum) {
|
||||
if (arguments.length === 1) {
|
||||
return parseInt(Math.random() * minNum + 1, 10)
|
||||
} else {
|
||||
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10)
|
||||
}
|
||||
}
|
||||
|
||||
export function multipleSum (...num) {
|
||||
let sum = 0
|
||||
|
||||
num.forEach(n => (sum += n))
|
||||
|
||||
return sum
|
||||
}
|
||||
|
||||
export function filterNull (arr) {
|
||||
const tmpArr = []
|
||||
|
||||
arr.forEach(v => ((v || v === 0) && tmpArr.push(v)))
|
||||
|
||||
return tmpArr
|
||||
}
|
||||
|
||||
export function getPointDistance (pointOne, pointTwo) {
|
||||
const minusX = Math.abs(pointOne[0] - pointTwo[0])
|
||||
|
||||
const minusY = Math.abs(pointOne[1] - pointTwo[1])
|
||||
|
||||
return Math.sqrt(minusX * minusX + minusY * minusY)
|
||||
}
|
||||
|
||||
export function getPointToLineDistance (point, linePointOne, linePointTwo) {
|
||||
const a = getPointDistance(point, linePointOne)
|
||||
const b = getPointDistance(point, linePointTwo)
|
||||
const c = getPointDistance(linePointOne, linePointTwo)
|
||||
|
||||
return 0.5 * Math.sqrt((a + b + c) * (a + b - c) * (a + c - b) * (b + c - a)) / c
|
||||
}
|
||||
|
||||
export function getArrayMaxMin (array) {
|
||||
if (!array) return false
|
||||
|
||||
return [getArrayMax(array), getArrayMin(array)]
|
||||
}
|
||||
|
||||
export function getArrayMax (array) {
|
||||
if (!array) return false
|
||||
|
||||
return Math.max(...filterNull(array).map(n =>
|
||||
n instanceof Array ? getArrayMax(n) : n))
|
||||
}
|
||||
|
||||
export function getArrayMin (array) {
|
||||
if (!array) return false
|
||||
|
||||
return Math.min(...filterNull(array).map(n =>
|
||||
n instanceof Array ? getArrayMin(n) : n))
|
||||
}
|
||||
|
||||
export function getAxisPointsPos ([max, min], values, axisOriginPos, axisWH, tagPos, horizon) {
|
||||
const minus = max - min
|
||||
|
||||
return values.map((value, i) => {
|
||||
if (!value && value !== 0) return false
|
||||
|
||||
if (value instanceof Array) {
|
||||
return value.map(v =>
|
||||
getAxisPointPos([max, min], v, axisOriginPos, axisWH, tagPos[i], horizon))
|
||||
}
|
||||
|
||||
const percent = (value - min) / minus
|
||||
|
||||
const length = percent * (horizon ? axisWH[0] : axisWH[1])
|
||||
|
||||
return horizon ? [
|
||||
axisOriginPos[0] + length,
|
||||
tagPos[i][1]
|
||||
] : [
|
||||
tagPos[i][0],
|
||||
axisOriginPos[1] - length
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
export function getAxisPointPos ([max, min], value, axisOriginPos, axisWH, tagPos, horizon) {
|
||||
if (!value && value !== 0) return false
|
||||
|
||||
const minus = max - min
|
||||
|
||||
const percent = (value - min) / minus
|
||||
|
||||
const length = percent * (horizon ? axisWH[0] : axisWH[1])
|
||||
|
||||
return horizon ? [
|
||||
axisOriginPos[0] + length,
|
||||
tagPos[1]
|
||||
] : [
|
||||
tagPos[0],
|
||||
axisOriginPos[1] - length
|
||||
]
|
||||
}
|
||||
|
||||
export default function (Vue) {
|
||||
Vue.prototype.deepClone = deepClone
|
||||
Vue.prototype.deleteArrayAllItems = deleteArrayAllItems
|
||||
Vue.prototype.debounce = debounce
|
||||
Vue.prototype.multipleSum = multipleSum
|
||||
Vue.prototype.randomExtend = randomExtend
|
||||
Vue.prototype.filterNull = filterNull
|
||||
Vue.prototype.getPointDistance = getPointDistance
|
||||
Vue.prototype.getPointToLineDistance = getPointToLineDistance
|
||||
Vue.prototype.getArrayMaxMin = getArrayMaxMin
|
||||
Vue.prototype.getArrayMax = getArrayMax
|
||||
Vue.prototype.getArrayMin = getArrayMin
|
||||
Vue.prototype.getAxisPointPos = getAxisPointPos
|
||||
Vue.prototype.getAxisPointsPos = getAxisPointsPos
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
const Document = r => require.ensure([], () => r(require('../views/demo/document.vue')), 'demo')
|
||||
|
||||
const BorderBox = r => require.ensure([], () => r(require('../views/demo/borderBox.vue')), 'demo')
|
||||
|
||||
const Decoration = r => require.ensure([], () => r(require('../views/demo/decoration.vue')), 'demo')
|
||||
|
||||
const Chart = r => require.ensure([], () => r(require('../views/demo/chart.vue')), 'demo')
|
||||
|
||||
const Other = r => require.ensure([], () => r(require('../views/demo/other.vue')), 'datav')
|
||||
|
||||
const Show = r => require.ensure([], () => r(require('../views/demo/show.vue')), 'datav')
|
||||
|
||||
export default [
|
||||
{
|
||||
path: 'document',
|
||||
name: 'document',
|
||||
component: Document
|
||||
},
|
||||
{
|
||||
path: 'borderBox',
|
||||
name: 'borderBox',
|
||||
component: BorderBox
|
||||
},
|
||||
{
|
||||
path: 'decoration',
|
||||
name: 'decoration',
|
||||
component: Decoration
|
||||
},
|
||||
{
|
||||
path: 'chart',
|
||||
name: 'chart',
|
||||
component: Chart
|
||||
},
|
||||
{
|
||||
path: 'other',
|
||||
name: 'other',
|
||||
component: Other
|
||||
},
|
||||
{
|
||||
path: 'show',
|
||||
name: 'show',
|
||||
component: Show
|
||||
}
|
||||
]
|
@ -1,55 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
|
||||
import Router from 'vue-router'
|
||||
|
||||
import demoChildren from './demo'
|
||||
|
||||
const Demo = r => require.ensure([], () => r(require('../views/demo/index.vue')), 'demo')
|
||||
|
||||
const Datav = r => require.ensure([], () => r(require('../views/datavEntrance/index.vue')), 'datav')
|
||||
|
||||
const View = r => require.ensure([], () => r(require('../views/dataView/index.vue')), 'datav')
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
export default new Router({
|
||||
scrollBehavior (to, from, savedPosition) {
|
||||
if (to.hash) {
|
||||
return {
|
||||
selector: to.hash
|
||||
}
|
||||
}
|
||||
},
|
||||
routes: [
|
||||
{
|
||||
path: '/demo',
|
||||
name: 'demo',
|
||||
component: Demo,
|
||||
redirect: { name: 'document' },
|
||||
children: [
|
||||
...demoChildren
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/datav',
|
||||
name: 'datav',
|
||||
component: Datav,
|
||||
redirect: '/datav/view',
|
||||
children: [
|
||||
{
|
||||
path: 'view',
|
||||
name: 'view',
|
||||
component: View
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
redirect: '/datav/view'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
redirect: { name: 'document' }
|
||||
}
|
||||
]
|
||||
})
|
@ -1,36 +0,0 @@
|
||||
<template>
|
||||
<div class="datav-page">
|
||||
<border-box-1>
|
||||
<div class="welcome">Welcome Data View Page</div>
|
||||
</border-box-1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DatavPage'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.datav-page {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #fff;
|
||||
|
||||
.border-box-1 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 100px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.welcome {
|
||||
margin-top: -100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,74 +0,0 @@
|
||||
<template>
|
||||
<div id="datav-entrance">
|
||||
<div class="datav-container" ref="data-root">
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DatavEntrance',
|
||||
data () {
|
||||
return {
|
||||
scale: 0,
|
||||
datavRoot: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init () {
|
||||
const { initConfig, setAppScale, bindReSizeEventHandler } = this
|
||||
|
||||
initConfig()
|
||||
|
||||
setAppScale()
|
||||
|
||||
bindReSizeEventHandler()
|
||||
},
|
||||
initConfig () {
|
||||
const { width, height } = screen
|
||||
|
||||
this.allWidth = width
|
||||
|
||||
const datavRoot = this.datavRoot = this.$refs['data-root']
|
||||
|
||||
datavRoot.style.width = `${width}px`
|
||||
datavRoot.style.height = `${height}px`
|
||||
},
|
||||
setAppScale () {
|
||||
const { allWidth, datavRoot } = this
|
||||
|
||||
const currentWidth = document.body.clientWidth
|
||||
|
||||
datavRoot.style.transform = `scale(${currentWidth / allWidth})`
|
||||
},
|
||||
bindReSizeEventHandler () {
|
||||
const { debounce, setAppScale } = this
|
||||
|
||||
if (!debounce) return
|
||||
|
||||
window.addEventListener('resize', debounce(100, setAppScale))
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const { init } = this
|
||||
|
||||
init()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
#datav-entrance {
|
||||
font-family: 'Avenir', Helvetica, Arial, sans-serif;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-size: 100%;
|
||||
background-image: url('../../assets/img/bg.png');
|
||||
|
||||
.datav-container {
|
||||
transform-origin: left top;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,96 +0,0 @@
|
||||
<template>
|
||||
<div id="border-box">
|
||||
<border-box-1 class="border-box-item">
|
||||
<div class="title">Border-Box-1</div>
|
||||
<highlight-code>
|
||||
<border-box-1></border-box-1>
|
||||
</highlight-code>
|
||||
</border-box-1>
|
||||
|
||||
<border-box-2 class="border-box-item">
|
||||
<div class="title">Border-Box-2</div>
|
||||
<highlight-code>
|
||||
<border-box-2></border-box-2>
|
||||
</highlight-code>
|
||||
</border-box-2>
|
||||
|
||||
<border-box-3 class="border-box-item">
|
||||
<div class="title">Border-Box-3</div>
|
||||
<highlight-code>
|
||||
<border-box-3></border-box-3>
|
||||
</highlight-code>
|
||||
</border-box-3>
|
||||
|
||||
<border-box-4 class="border-box-item">
|
||||
<div class="title">Border-Box-4</div>
|
||||
<highlight-code>
|
||||
<border-box-4></border-box-4>
|
||||
</highlight-code>
|
||||
</border-box-4>
|
||||
|
||||
<border-box-4 class="border-box-item" :reverse="true">
|
||||
<div class="title">Border-Box-4(reverse)</div>
|
||||
<highlight-code>
|
||||
<border-box-4 :reverse="true" ></border-box-4>
|
||||
</highlight-code>
|
||||
</border-box-4>
|
||||
|
||||
<border-box-5 class="border-box-item">
|
||||
<div class="title">Border-Box-5</div>
|
||||
<highlight-code>
|
||||
<border-box-5></border-box-5>
|
||||
</highlight-code>
|
||||
</border-box-5>
|
||||
|
||||
<border-box-5 class="border-box-item" :reverse="true">
|
||||
<div class="title">Border-Box-5(reverse)</div>
|
||||
<highlight-code>
|
||||
<border-box-5 :reverse="true" ></border-box-5>
|
||||
</highlight-code>
|
||||
</border-box-5>
|
||||
|
||||
<border-box-6 class="border-box-item">
|
||||
<div class="title">Border-Box-6</div>
|
||||
<highlight-code>
|
||||
<border-box-6></border-box-6>
|
||||
</highlight-code>
|
||||
</border-box-6>
|
||||
|
||||
<border-box-7 class="border-box-item">
|
||||
<div class="title">Border-Box-7</div>
|
||||
<highlight-code>
|
||||
<border-box-7></border-box-7>
|
||||
</highlight-code>
|
||||
</border-box-7>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BorderBox'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
#border-box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
padding-bottom: 100px;
|
||||
|
||||
.border-box-item {
|
||||
position: relative;
|
||||
width: 50%;
|
||||
height: 300px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.title {
|
||||
text-indent: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,415 +0,0 @@
|
||||
<template>
|
||||
<div id="chart">
|
||||
<side-nav :nav="navData" />
|
||||
|
||||
<attention />
|
||||
|
||||
<column-chart-demo />
|
||||
|
||||
<polyline-chart-demo />
|
||||
|
||||
<point-chart-demo />
|
||||
|
||||
<radar-chart-demo />
|
||||
|
||||
<div id="capsule-chart" />
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<capsule-chart :data="capsuleChartData" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Capsule-Chart</div>
|
||||
<highlight-code>
|
||||
<capsule-chart :data="data" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
data: {
|
||||
// 必填项
|
||||
data: [
|
||||
{
|
||||
value: 85,
|
||||
title: '收费系统'
|
||||
},...
|
||||
],
|
||||
// 必填项 依次循环使用
|
||||
color: ['#00baff', '#3de7c9', ...]
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<div id="arc-ring-chart" />
|
||||
|
||||
<border-box-7 class="chart-item" :reverse="true">
|
||||
<arc-ring-chart :data="arcRingChartData" class="chart" />
|
||||
<div class="config-info">
|
||||
<div class="title">Arc-Ring-Chart</div>
|
||||
|
||||
<highlight-code>
|
||||
<capsule-chart :data="data" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
data: {
|
||||
// 必填项
|
||||
data: [
|
||||
{
|
||||
value: 38,
|
||||
title: '监控系统'
|
||||
},...
|
||||
],
|
||||
// 必填项 依次循环使用
|
||||
color: ['#00c0ff', '#3de7c9', ...]
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<div id="concentric-arc-chart" />
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<concentric-arc-chart :data="concentricArcChartData" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Concentric-Arc-Chart</div>
|
||||
|
||||
<highlight-code>
|
||||
<concentric-arc-chart :data="data" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
data: {
|
||||
// 必填项
|
||||
data: [
|
||||
{
|
||||
value: 0.38,
|
||||
title: '8小时以内'
|
||||
},...
|
||||
],
|
||||
// 必填项 多个颜色自动生成渐变色
|
||||
color: ['#00c0ff', '#3de7c9']
|
||||
arcArea: [0.3, 0.7], // 非必须
|
||||
arcGap: 5, // 非必须
|
||||
fontSize: 12 // 非必须
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<div id="ring-chart" />
|
||||
|
||||
<border-box-7 class="chart-item" :reverse="true">
|
||||
<ring-chart :data="ringChart1" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Ring-Chart</div>
|
||||
|
||||
<highlight-code>
|
||||
<ring-chart :data="data" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
data: {
|
||||
// 必填项
|
||||
data: [
|
||||
{
|
||||
value: 1315,
|
||||
title: '收费站'
|
||||
},...
|
||||
],
|
||||
// 必填项 依次循环使用
|
||||
color: ['#00baff', '#3de7c9'],
|
||||
// 为false时 无动态效果
|
||||
active: true
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<ring-chart :data="ringChart2" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Ring-chart</div>
|
||||
|
||||
<highlight-code>
|
||||
<ring-chart :data="data" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
value: 1315,
|
||||
title: '收费站'
|
||||
},...
|
||||
],
|
||||
// 非必须 依次循环使用
|
||||
color: ['#00baff', '#3de7c9'],
|
||||
// 为true时 有动态效果
|
||||
active: false,
|
||||
// 非必须 该项可设置百分比精度 active为false时无效
|
||||
// fixed: 2
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<!-- <highlight-code class="chart-item" :reverse="true">
|
||||
<polyline-chart :data="polylineChartData" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="header">Polyline-chart</div>
|
||||
<pre>
|
||||
</pre>
|
||||
</div>
|
||||
</highlight-code> -->
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import attention from './chart/attention.vue'
|
||||
|
||||
import columnChartDemo from './chart/columnChartDemo'
|
||||
|
||||
import polylineChartDemo from './chart/polylineChartDemo'
|
||||
|
||||
import pointChartDemo from './chart/pointChartDemo'
|
||||
|
||||
import radarChartDemo from './chart/radarChartDemo'
|
||||
|
||||
export default {
|
||||
name: 'Chart',
|
||||
components: {
|
||||
attention,
|
||||
columnChartDemo,
|
||||
polylineChartDemo,
|
||||
pointChartDemo,
|
||||
radarChartDemo
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
navData: [
|
||||
{
|
||||
title: 'Attention',
|
||||
target: 'attention'
|
||||
},
|
||||
{
|
||||
title: 'Column-Chart',
|
||||
target: 'column-chart'
|
||||
},
|
||||
{
|
||||
title: 'Polyline-Chart',
|
||||
target: 'polyline-chart'
|
||||
},
|
||||
{
|
||||
title: 'Point-Chart',
|
||||
target: 'point-chart'
|
||||
},
|
||||
{
|
||||
title: 'Radar-Chart',
|
||||
target: 'radar-chart'
|
||||
},
|
||||
{
|
||||
title: 'Capsule-Chart',
|
||||
target: 'capsule-chart'
|
||||
},
|
||||
{
|
||||
title: 'Arc-Ring-Chart',
|
||||
target: 'arc-ring-chart'
|
||||
},
|
||||
{
|
||||
title: 'Concentric-Arc-Chart',
|
||||
target: 'concentric-arc-chart'
|
||||
},
|
||||
{
|
||||
title: 'Ring-Chart',
|
||||
target: 'ring-chart'
|
||||
}
|
||||
],
|
||||
|
||||
capsuleChartData: {
|
||||
data: [
|
||||
{
|
||||
value: 85,
|
||||
title: '收费系统'
|
||||
},
|
||||
{
|
||||
value: 44,
|
||||
title: '通信系统'
|
||||
},
|
||||
{
|
||||
value: 125,
|
||||
title: '监控系统'
|
||||
},
|
||||
{
|
||||
value: 110,
|
||||
title: '供配电系统'
|
||||
},
|
||||
{
|
||||
value: 66,
|
||||
title: '其他'
|
||||
}
|
||||
],
|
||||
color: [
|
||||
'#00baff',
|
||||
'#3de7c9',
|
||||
'#ffffff',
|
||||
'#ffc53d',
|
||||
'#469f4b'
|
||||
]
|
||||
},
|
||||
|
||||
arcRingChartData: {
|
||||
data: [
|
||||
{
|
||||
value: 19,
|
||||
title: '监控系统'
|
||||
},
|
||||
{
|
||||
value: 16,
|
||||
title: '收费系统'
|
||||
},
|
||||
{
|
||||
value: 24,
|
||||
title: '通信系统'
|
||||
},
|
||||
{
|
||||
value: 14,
|
||||
title: '供配电系统'
|
||||
},
|
||||
{
|
||||
value: 27,
|
||||
title: '其他'
|
||||
}
|
||||
],
|
||||
color: ['#00c0ff', '#3de7c9', '#fff']
|
||||
},
|
||||
|
||||
concentricArcChartData: {
|
||||
data: [
|
||||
{
|
||||
value: 0.38,
|
||||
title: '8小时以内'
|
||||
},
|
||||
{
|
||||
value: 0.57,
|
||||
title: '24小时以内'
|
||||
},
|
||||
{
|
||||
value: 0.7,
|
||||
title: '48小时以内'
|
||||
},
|
||||
{
|
||||
value: 0.78,
|
||||
title: '72小时以内'
|
||||
},
|
||||
{
|
||||
value: 0.22,
|
||||
title: '大于72小时'
|
||||
}
|
||||
],
|
||||
color: ['#00c0ff', '#3de7c9'],
|
||||
arcArea: [0.3, 0.7],
|
||||
arcGap: 5,
|
||||
fontSize: 12
|
||||
},
|
||||
|
||||
ringChart1: {
|
||||
data: [
|
||||
{
|
||||
value: 1315,
|
||||
title: '收费站'
|
||||
},
|
||||
{
|
||||
value: 415,
|
||||
title: '监控中心'
|
||||
},
|
||||
{
|
||||
value: 90,
|
||||
title: '道路外场'
|
||||
},
|
||||
{
|
||||
value: 317,
|
||||
title: '其他'
|
||||
}
|
||||
],
|
||||
color: [
|
||||
'#00baff',
|
||||
'#3de7c9',
|
||||
'#ffffff',
|
||||
'#ffc53d',
|
||||
'#469f4b'
|
||||
],
|
||||
active: true
|
||||
},
|
||||
|
||||
ringChart2: {
|
||||
data: [
|
||||
{
|
||||
value: 1315,
|
||||
title: '收费站'
|
||||
},
|
||||
{
|
||||
value: 415,
|
||||
title: '监控中心'
|
||||
},
|
||||
{
|
||||
value: 90,
|
||||
title: '道路外场'
|
||||
},
|
||||
{
|
||||
value: 317,
|
||||
title: '其他'
|
||||
}
|
||||
],
|
||||
color: [
|
||||
'#00baff',
|
||||
'#3de7c9',
|
||||
'#ffffff',
|
||||
'#ffc53d',
|
||||
'#469f4b'
|
||||
],
|
||||
active: false
|
||||
},
|
||||
|
||||
colors: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
#chart {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.chart-item {
|
||||
width: 80%;
|
||||
min-height: 300px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 20px 0px;
|
||||
margin-left: 20%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.chart {
|
||||
width: 400px;
|
||||
height: 300px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.config-info {
|
||||
padding: 0px 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.highlight-code {
|
||||
margin: -30px 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,149 +0,0 @@
|
||||
<template>
|
||||
<border-box-7 class="attention" id="attention">
|
||||
<div class="title">Attention</div>
|
||||
|
||||
<div class="title">Colors</div>
|
||||
|
||||
<div class="text-info">
|
||||
下列组件颜色配置均绑定在节点的colors属性上
|
||||
</div>
|
||||
|
||||
<div class="text-info">
|
||||
若未绑定将自动使用默认配色
|
||||
</div>
|
||||
|
||||
<div class="text-info">
|
||||
colors所绑变量应为hex十六进制色的数组,示例如下
|
||||
</div>
|
||||
|
||||
<highlight-code>
|
||||
<chart :data="data" :colors="color" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 修改默认配色方案 可直接修改./src/config/color.js
|
||||
colors: ['#9cf4a7', '#66d7ee', '#eee966', '#a866ee', '#ee8f66', '#ee66aa']
|
||||
// 数组内颜色将自动循环使用
|
||||
</highlight-code>
|
||||
|
||||
<div class="text-info">
|
||||
如在特殊颜色配置属性中使用colors关键字,将自动将该属性配置指向colors
|
||||
</div>
|
||||
|
||||
<div class="text-info">
|
||||
下列组件均不再展示colors属性绑定的变量
|
||||
</div>
|
||||
|
||||
<div class="title">Axis</div>
|
||||
|
||||
<div class="text-info">
|
||||
下列组件中多有使用坐标轴 坐标轴配置如下
|
||||
</div>
|
||||
|
||||
<highlight-code class="center-code">
|
||||
// 坐标轴分为四部分 x y ax ay
|
||||
// ax ay 即为x y轴相对的坐标轴
|
||||
// 如果要使ax ay生效 data中应配置 againstAxis: true
|
||||
axisData: {
|
||||
data: [
|
||||
{ // 该组数据基于 x y 轴
|
||||
data: [123, 123, 123, '', 123]
|
||||
},
|
||||
{ // 改组数据基于 ax
|
||||
data: [123, 123, 123, '', 123],
|
||||
againstAxis: true
|
||||
}
|
||||
],
|
||||
x: {
|
||||
// 必须 x轴展示标签
|
||||
data: ['label1', 'label2', 'label3', 'label4'],
|
||||
// 非必须 单位
|
||||
unit: '单位',
|
||||
// 非必须 禁止绘制该轴坐标线
|
||||
noAxisLine: true,
|
||||
// 非必须 禁止绘制该轴展示标签
|
||||
noAxisTag: true,
|
||||
// 非必须 该轴偏移量
|
||||
offset: 30,
|
||||
// 非必须 是否绘制网格
|
||||
grid: true,
|
||||
// 非必须 设置网格线条为虚线
|
||||
gridType: 'dashed',
|
||||
// 非必须 网格虚线dashed
|
||||
gridLineDash: [2, 2],
|
||||
// 非必须 网格颜色 多个则循环使用
|
||||
gridColor: 'colors' | '#123456' | ['#123', '#456']
|
||||
// 非必须 设置该轴标签before字符
|
||||
tagBefore: 'before',
|
||||
// 非必须 设置该轴标签after字符
|
||||
tagAfter: 'after',
|
||||
// 非必须 设置x轴 展示标签旋转度数 仅在x轴有效
|
||||
rotate: 20
|
||||
},
|
||||
// y轴 也可设置data 设置data 下列专有配置自动失效
|
||||
y: {
|
||||
// 非必须 强制最大值
|
||||
max: 999,
|
||||
// 非必须 强制最小值
|
||||
min: 0,
|
||||
// 非必须 强制数值展示个数
|
||||
num: 5,
|
||||
// 非必须 设置数据精度
|
||||
fixed: 2
|
||||
},
|
||||
// 非必须 水平坐标轴 配置该项 x y数据应对调
|
||||
// 并非所有图表有效
|
||||
horizon: true
|
||||
}
|
||||
// 具体见示例
|
||||
</highlight-code>
|
||||
|
||||
<div class="title">Label-Line</div>
|
||||
|
||||
<div class="text-info">
|
||||
下列组件中多有使用坐标轴 坐标轴常用配置如下
|
||||
</div>
|
||||
|
||||
<highlight-code class="center-code">
|
||||
// label-line 即图标底部标签
|
||||
labelLineData: {
|
||||
// 必须 标签文字
|
||||
data: ['标签1', '标签2', ...],
|
||||
// 非必须 设置标签前置色块颜色 多个则循环使用
|
||||
color: '#2b7bfb',
|
||||
// 非必须 设置标签前置色块形状 rectangle 长方形 rect正方形
|
||||
type: 'rectangle'
|
||||
}
|
||||
// 具体见示例
|
||||
</highlight-code>
|
||||
|
||||
<div id="column-chart" />
|
||||
</border-box-7>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Attention'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
#attention {
|
||||
width: 80%;
|
||||
margin-left: 20%;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.highlight-code {
|
||||
margin: -40px 0px;
|
||||
}
|
||||
|
||||
.center-code {
|
||||
text-align: left;
|
||||
padding: 0px 100px;
|
||||
width: 500px;
|
||||
margin-left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,614 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<border-box-7 class="chart-item">
|
||||
<column-chart :data="columnChartData1" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Column-Chart</div>
|
||||
<highlight-code>
|
||||
<column-chart :data="data" :colors="colors" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
data: [150, 290, 420, 200, 350, 219],
|
||||
fillColor: ['#247efc', '#ff2fdb'],
|
||||
// 非必需 强制该列数据值标签颜色
|
||||
// inherit 即为继承本列颜色 继承优先级为 fillColor lineColor colors
|
||||
valueTextColor: 'inherit'
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳']
|
||||
},
|
||||
y: {
|
||||
unit: '辆'
|
||||
},
|
||||
labelLine: {
|
||||
color: '#2b7bfb',
|
||||
data: ['车流量'],
|
||||
type: 'rectangle'
|
||||
},
|
||||
// 非必需 展示数据值标签
|
||||
showValueText: true
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<column-chart :data="columnChartData2" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Column-Chart</div>
|
||||
<highlight-code>
|
||||
<column-chart :data="data" :colors="colors" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 相同配置不再赘述
|
||||
data: {
|
||||
y: {
|
||||
grid: true,
|
||||
gridLineType: 'dashed',
|
||||
gridLineDash: [2, 2],
|
||||
num: 6
|
||||
},
|
||||
showColumnBG: true,
|
||||
columnBGColor: 'rgba(100, 100, 100, 0.3)'
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<column-chart :data="columnChartData3" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Column-Chart</div>
|
||||
<highlight-code>
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 相同配置不再赘述
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
data: [150, 290, 420, 200, 350, 219],
|
||||
fillColor: '#247efc'
|
||||
},
|
||||
{
|
||||
data: [
|
||||
[35, 70, 40],
|
||||
[74, 180, 45],
|
||||
[37, 200, 145],
|
||||
[35, 89, 30],
|
||||
[65, 100, 48],
|
||||
[55, 90, 70]
|
||||
],
|
||||
fillColor: ['#ff2fdb', '#e3b4a2', '#fafb5d']
|
||||
}
|
||||
]
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<column-chart :data="columnChartData4" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Column-Chart</div>
|
||||
<highlight-code>
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 相同配置不再赘述
|
||||
data:{
|
||||
data: [
|
||||
{
|
||||
data: [150, 290, 420, 200, 350, 219],
|
||||
fillColor: ['#247efc', '#ff2fdb']
|
||||
},
|
||||
{
|
||||
data: [130, 313, 392, 180, 400, 188],
|
||||
fillColor: ['#00BAFF', '#3DE7C9']
|
||||
}
|
||||
],
|
||||
// 非必须 指定圆角柱
|
||||
roundColumn: true,
|
||||
// 非必须 指定柱间间隔
|
||||
spaceBetween: true,
|
||||
// 非必须 指定局部渐变
|
||||
localGradient: true
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<column-chart :data="columnChartData5" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Column-Chart</div>
|
||||
<highlight-code>
|
||||
<column-chart :data="data" :colors="colors" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 相同配置不再赘述
|
||||
data: [
|
||||
{
|
||||
data: [150, 290, 420, 200, 350, 219],
|
||||
fillColor: ['#247efc', '#ff2fdb'],
|
||||
// 非必须 指定左边梯形柱 该属性在单柱数据生效 且不能设置roundColumn
|
||||
type: 'leftEchelon'
|
||||
},
|
||||
{
|
||||
data: [130, 313, 392, 180, 400, 188],
|
||||
fillColor: ['#00BAFF', '#3DE7C9'],
|
||||
// 非必须 指定右边梯形柱
|
||||
type: 'rightEchelon'
|
||||
},
|
||||
// 非必须 显示数值
|
||||
showValueText: true,
|
||||
// 非必须 设置全局数据值标签颜色
|
||||
valueTextColor: '#bbb'
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<column-chart :data="columnChartData6" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Column-Chart</div>
|
||||
<highlight-code>
|
||||
<column-chart :data="data" :colors="colors" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 相同配置不再赘述
|
||||
data: {
|
||||
data: [
|
||||
...
|
||||
{
|
||||
...
|
||||
type: 'polyline',
|
||||
againstAxis: true,
|
||||
lineColor: '#ff2fdb',
|
||||
pointColor: '#3de7c9'
|
||||
}
|
||||
],
|
||||
x: {
|
||||
offset: 40,
|
||||
// 旋转角度
|
||||
rotate: 20
|
||||
},
|
||||
y: {
|
||||
tagAfter: 'ml'
|
||||
},
|
||||
ay: {
|
||||
afterTag: '°C'
|
||||
}
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<column-chart :data="columnChartData7" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Column-Chart</div>
|
||||
<highlight-code>
|
||||
<column-chart :data="data" :colors="colors" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 相同配置不再赘述
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
data: [330, 290, 330, 400, 330, 290, 330],
|
||||
fillColor: ['rgba(0, 186, 255, 0.3)', 'rgba(0, 186, 255, 0)']
|
||||
},
|
||||
{
|
||||
data: [260, 265, 280, 450, 280, 265, 260],
|
||||
type: 'smoothline',
|
||||
lineType: 'dashed',
|
||||
againstAxis: true,
|
||||
lineColor: '#3de7c9',
|
||||
fillColor: ['rgba(0, 219, 149, 0.3)', 'rgba(0, 219, 149, 0)']
|
||||
}
|
||||
]
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<column-chart :data="columnChartData8" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Column-Chart</div>
|
||||
<highlight-code>
|
||||
<column-chart :data="data" :colors="colors" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 相同配置不再赘述
|
||||
data: {
|
||||
x: {
|
||||
unit: '辆',
|
||||
grid: true,
|
||||
gridLineType: 'dashed',
|
||||
gridLineDash: [2, 2]
|
||||
},
|
||||
y: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳']
|
||||
},
|
||||
// 非必须 水平图
|
||||
horizon: true
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<column-chart :data="columnChartData9" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Column-Chart</div>
|
||||
<highlight-code>
|
||||
<column-chart :data="data" :colors="colors" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 相同配置不再赘述
|
||||
data: {
|
||||
x: {
|
||||
noAxisLine: true,
|
||||
noAxisTag: true,
|
||||
offset: 10
|
||||
},
|
||||
y: {
|
||||
noAxisLine: true,
|
||||
noAxisTag: true,
|
||||
offset: 1
|
||||
},
|
||||
showValueText: true,
|
||||
// 非必须 设置数值文字颜色
|
||||
valueTextColor: '#fff',
|
||||
// 非必须 设置数值文字相对偏移量
|
||||
valueTextOffset: [0, 15]
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<div id="polyline-chart" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ColumnChartDemo',
|
||||
data () {
|
||||
return {
|
||||
columnChartData1: {
|
||||
data: [
|
||||
{
|
||||
data: [150, 290, 420, 200, 350, 219],
|
||||
fillColor: ['#247efc', '#ff2fdb'],
|
||||
valueTextColor: 'inherit'
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳']
|
||||
},
|
||||
y: {
|
||||
unit: '辆'
|
||||
},
|
||||
labelLine: {
|
||||
color: '#2b7bfb',
|
||||
data: ['车流量'],
|
||||
type: 'rectangle'
|
||||
},
|
||||
showValueText: true
|
||||
},
|
||||
|
||||
columnChartData2: {
|
||||
data: [
|
||||
{
|
||||
data: [150, 290, 420, 200, 350, 219],
|
||||
fillColor: ['#247efc', '#ff2fdb']
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳']
|
||||
},
|
||||
y: {
|
||||
unit: '辆',
|
||||
grid: true,
|
||||
gridLineType: 'dashed',
|
||||
gridLineDash: [2, 2],
|
||||
num: 6
|
||||
},
|
||||
labelLine: {
|
||||
color: '#2b7bfb',
|
||||
data: ['车流量'],
|
||||
type: 'rectangle'
|
||||
},
|
||||
showColumnBG: true,
|
||||
columnBGColor: 'rgba(100, 100, 100, 0.3)'
|
||||
},
|
||||
|
||||
columnChartData3: {
|
||||
data: [
|
||||
{
|
||||
data: [150, 290, 420, 200, 350, 219],
|
||||
fillColor: '#247efc'
|
||||
},
|
||||
{
|
||||
data: [
|
||||
[35, 70, 40],
|
||||
[74, 180, 45],
|
||||
[37, 200, 145],
|
||||
[35, 89, 30],
|
||||
[65, 100, 48],
|
||||
[55, 90, 70]
|
||||
],
|
||||
fillColor: ['#ff2fdb', '#e3b4a2', '#fafb5d']
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳']
|
||||
},
|
||||
y: {
|
||||
unit: '万元',
|
||||
grid: true,
|
||||
gridLineType: 'dashed',
|
||||
gridLineDash: [2, 2],
|
||||
min: 0
|
||||
},
|
||||
labelLine: {
|
||||
color: ['#247efc', '#ff2fdb', '#e3b4a2', '#fafb5d'],
|
||||
data: ['玩具', '食品', '服装', '电器'],
|
||||
type: 'rectangle'
|
||||
},
|
||||
showColumnBG: true,
|
||||
columnBGColor: 'rgba(100, 100, 100, 0.3)'
|
||||
},
|
||||
|
||||
columnChartData4: {
|
||||
data: [
|
||||
{
|
||||
data: [150, 290, 420, 200, 350, 219],
|
||||
fillColor: ['#247efc', '#ff2fdb']
|
||||
},
|
||||
{
|
||||
data: [130, 313, 392, 180, 400, 188],
|
||||
fillColor: ['#00BAFF', '#3DE7C9']
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳']
|
||||
},
|
||||
y: {
|
||||
grid: true,
|
||||
gridLineType: 'dashed',
|
||||
gridLineDash: [2, 2],
|
||||
unit: '辆'
|
||||
},
|
||||
labelLine: {
|
||||
color: ['#ff2fdb', '#3DE7C9'],
|
||||
data: ['同期', '环期'],
|
||||
type: 'rectangle'
|
||||
},
|
||||
roundColumn: true,
|
||||
spaceBetween: true,
|
||||
localGradient: true
|
||||
},
|
||||
|
||||
columnChartData5: {
|
||||
data: [
|
||||
{
|
||||
data: [150, 290, 420, 200, 350, 219],
|
||||
fillColor: ['#247efc', '#ff2fdb'],
|
||||
type: 'leftEchelon'
|
||||
},
|
||||
{
|
||||
data: [130, 313, 392, 180, 400, 188],
|
||||
fillColor: ['#00BAFF', '#3DE7C9'],
|
||||
type: 'rightEchelon'
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳']
|
||||
},
|
||||
y: {
|
||||
grid: true,
|
||||
gridLineType: 'dashed',
|
||||
gridLineDash: [2, 2],
|
||||
unit: '辆',
|
||||
num: 7
|
||||
},
|
||||
labelLine: {
|
||||
color: ['#ff2fdb', '#3DE7C9'],
|
||||
data: ['同期', '环期'],
|
||||
type: 'rectangle'
|
||||
},
|
||||
showValueText: true,
|
||||
spaceBetween: true,
|
||||
valueTextColor: '#bbb'
|
||||
},
|
||||
|
||||
columnChartData6: {
|
||||
data: [
|
||||
{
|
||||
data: [175, 125, 90, 130, 45, 65, 65, 47, 50, 52, 45, 37],
|
||||
fillColor: ['#247efc', '#ff2fdb']
|
||||
},
|
||||
{
|
||||
data: [210, 142, 128, 142, 63, 72, 68, 57, 54, 60, 49, 42],
|
||||
fillColor: ['#00BAFF', '#3DE7C9']
|
||||
},
|
||||
{
|
||||
data: [23, 18, 16, 14, 10, 8, 6, 6, 6, 6, 6, 5],
|
||||
type: 'polyline',
|
||||
againstAxis: true,
|
||||
lineColor: '#ff2fdb',
|
||||
pointColor: '#3de7c9'
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: [
|
||||
'一月份', '二月份',
|
||||
'三月份', '四月份',
|
||||
'五月份', '六月份',
|
||||
'七月份', '八月份',
|
||||
'九月份', '十月份',
|
||||
'十一月份', '十二月份'
|
||||
],
|
||||
offset: 40,
|
||||
rotate: 20
|
||||
},
|
||||
y: {
|
||||
grid: true,
|
||||
gridLineType: 'dashed',
|
||||
gridLineDash: [2, 2],
|
||||
min: 0,
|
||||
max: 250,
|
||||
num: 6,
|
||||
tagAfter: 'ml'
|
||||
},
|
||||
ay: {
|
||||
min: 0,
|
||||
max: 25,
|
||||
num: 6,
|
||||
tagAfter: '°C'
|
||||
},
|
||||
labelLine: {
|
||||
color: ['#ff2fdb', '#3DE7C9'],
|
||||
data: ['同期', '环期'],
|
||||
type: 'rectangle'
|
||||
},
|
||||
roundColumn: true,
|
||||
localGradient: true,
|
||||
spaceBetween: true
|
||||
},
|
||||
|
||||
columnChartData7: {
|
||||
data: [
|
||||
{
|
||||
data: [330, 290, 330, 400, 330, 290, 330],
|
||||
fillColor: ['rgba(0, 186, 255, 0.3)', 'rgba(0, 186, 255, 0)']
|
||||
},
|
||||
{
|
||||
data: [260, 265, 280, 450, 280, 265, 260],
|
||||
type: 'smoothline',
|
||||
lineType: 'dashed',
|
||||
againstAxis: true,
|
||||
lineColor: '#3de7c9',
|
||||
fillColor: ['rgba(0, 219, 149, 0.3)', 'rgba(0, 219, 149, 0)']
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳', '漯河']
|
||||
},
|
||||
y: {
|
||||
unit: '辆',
|
||||
grid: true,
|
||||
gridLineType: 'dashed',
|
||||
gridLineDash: [2, 2],
|
||||
num: 6,
|
||||
min: 0,
|
||||
max: 500
|
||||
},
|
||||
labelLine: {
|
||||
color: '#2b7bfb',
|
||||
data: ['车流量'],
|
||||
type: 'rectangle'
|
||||
},
|
||||
ay: {
|
||||
num: 6,
|
||||
min: 100,
|
||||
max: 500
|
||||
}
|
||||
},
|
||||
|
||||
columnChartData8: {
|
||||
data: [
|
||||
{
|
||||
data: [150, 290, 420, 200, 350, 219],
|
||||
fillColor: ['#247efc', '#ff2fdb'],
|
||||
type: 'leftEchelon'
|
||||
},
|
||||
{
|
||||
data: [130, 313, 392, 180, 400, 188],
|
||||
fillColor: ['#00BAFF', '#3DE7C9'],
|
||||
type: 'rightEchelon'
|
||||
}
|
||||
],
|
||||
x: {
|
||||
unit: '辆',
|
||||
grid: true,
|
||||
gridLineType: 'dashed',
|
||||
gridLineDash: [2, 2]
|
||||
},
|
||||
y: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳']
|
||||
},
|
||||
labelLine: {
|
||||
color: '#2b7bfb',
|
||||
data: ['车流量'],
|
||||
type: 'rectangle'
|
||||
},
|
||||
horizon: true,
|
||||
showColumnBG: true,
|
||||
localGradient: true,
|
||||
spaceBetween: true
|
||||
},
|
||||
|
||||
columnChartData9: {
|
||||
data: [
|
||||
{
|
||||
data: [150, 290, 420, 200, 350, 219],
|
||||
fillColor: ['#247efc', '#ff2fdb']
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳'],
|
||||
noAxisLine: true,
|
||||
noAxisTag: true,
|
||||
offset: 10
|
||||
},
|
||||
y: {
|
||||
noAxisLine: true,
|
||||
noAxisTag: true,
|
||||
offset: 1
|
||||
},
|
||||
labelLine: {
|
||||
color: '#2b7bfb',
|
||||
data: ['车流量'],
|
||||
type: 'rectangle'
|
||||
},
|
||||
showColumnBG: true,
|
||||
showValueText: true,
|
||||
valueTextColor: '#fff',
|
||||
valueTextOffset: [0, 15]
|
||||
},
|
||||
|
||||
colors: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
</style>
|
@ -1,219 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<border-box-7 class="chart-item">
|
||||
<point-chart :data="pointChartData1" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Point-Chart</div>
|
||||
<highlight-code>
|
||||
<point-chart :data="data" :colors="colors" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
data: [
|
||||
'', '',
|
||||
[280, 265, 240, 200, 180],...
|
||||
]
|
||||
},
|
||||
{
|
||||
data: [
|
||||
'', '', '', '', '',
|
||||
'', '', '', '', '',
|
||||
[357, 222, 82, 355],...
|
||||
]
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: [ '', '',
|
||||
'西峡', '', '', '周口', '', '',
|
||||
'南阳', '', '', '驻马店', '', '',
|
||||
'郑州', '', '', '洛阳', '', ''
|
||||
],
|
||||
grid: true,
|
||||
gridLineType: 'dashed',
|
||||
gridLineDash: [2, 2]
|
||||
},
|
||||
y: {
|
||||
min: 0,
|
||||
num: 6,
|
||||
max: 500
|
||||
}
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<point-chart :data="pointChartData2" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Point-Chart</div>
|
||||
<highlight-code>
|
||||
<point-chart :data="data" :colors="colors" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 相同配置不再赘述
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
data: ...,
|
||||
// 非必须 设置该项 点内部自动透明
|
||||
// 如果设置了fillColor 其应该为16进制色 否则无法进行透明计算
|
||||
opacity: 0.5
|
||||
},
|
||||
{
|
||||
data: ...,
|
||||
// 非必须 设置局部点半径
|
||||
radius: 5,
|
||||
// 非必须 设置边线颜色
|
||||
edgeColor: '#ff5ca9',
|
||||
// 非必须 设置点内部填充色
|
||||
fillColor: 'rgba(0, 186, 255, 0.5)'
|
||||
}
|
||||
],
|
||||
// 非必须 设置全局点半径
|
||||
radius: 4
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<div id="radar-chart" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PointChartDemo',
|
||||
data () {
|
||||
return {
|
||||
pointChartData1: {
|
||||
data: [
|
||||
{
|
||||
data: [
|
||||
'', '',
|
||||
[280, 265, 240, 200, 180],
|
||||
[320, 200, 190, 255, 260],
|
||||
[330, 222, 190, 255, 270],
|
||||
[325, 260, 220, 190, 255],
|
||||
[300, 245, 215, 255, 270],
|
||||
[280, 250, 190, 255, 270]
|
||||
]
|
||||
},
|
||||
{
|
||||
data: [
|
||||
'', '',
|
||||
'', '',
|
||||
'', '',
|
||||
'', '',
|
||||
'', '',
|
||||
[357, 222, 82, 355],
|
||||
[56, 25, 156],
|
||||
[70, 251, 425, 300, 278, 315],
|
||||
[79, 52, 40, 250, 160],
|
||||
[70, 251, 425, 300, 278, 315],
|
||||
[79, 52, 40, 180, 240],
|
||||
[79, 52, 40],
|
||||
[60, 56, 56],
|
||||
'', ''
|
||||
]
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: [ '', '',
|
||||
'西峡', '', '',
|
||||
'周口', '', '',
|
||||
'南阳', '', '',
|
||||
'驻马店', '', '',
|
||||
'郑州', '', '',
|
||||
'洛阳', '', ''
|
||||
],
|
||||
grid: true,
|
||||
gridLineType: 'dashed',
|
||||
gridLineDash: [2, 2]
|
||||
},
|
||||
y: {
|
||||
min: 0,
|
||||
num: 6,
|
||||
max: 500
|
||||
},
|
||||
labelLine: {
|
||||
data: ['同期', '环期'],
|
||||
type: 'rectangle'
|
||||
}
|
||||
},
|
||||
|
||||
pointChartData2: {
|
||||
data: [
|
||||
{
|
||||
data: [
|
||||
'', '',
|
||||
[280, 265, 240, 200, 180],
|
||||
[320, 200, 190, 255, 260],
|
||||
[330, 222, 190, 255, 270],
|
||||
[325, 260, 220, 190, 255],
|
||||
[300, 245, 215, 255, 270],
|
||||
[280, 250, 190, 255, 270]
|
||||
],
|
||||
opacity: 0.5
|
||||
},
|
||||
{
|
||||
data: [
|
||||
'', '',
|
||||
'', '',
|
||||
'', '',
|
||||
'', '',
|
||||
'', '',
|
||||
[357, 222, 82, 355],
|
||||
[56, 25, 156],
|
||||
[70, 251, 425, 300, 278, 315],
|
||||
[79, 52, 40, 250, 160],
|
||||
[70, 251, 425, 300, 278, 315],
|
||||
[79, 52, 40, 180, 240],
|
||||
[79, 52, 40],
|
||||
[60, 56, 56],
|
||||
'', ''
|
||||
],
|
||||
radius: 5,
|
||||
edgeColor: '#ff5ca9',
|
||||
fillColor: 'rgba(0, 186, 255, 0.5)'
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: [ '', '',
|
||||
'西峡', '', '',
|
||||
'周口', '', '',
|
||||
'南阳', '', '',
|
||||
'驻马店', '', '',
|
||||
'郑州', '', '',
|
||||
'洛阳', '', ''
|
||||
],
|
||||
grid: true,
|
||||
gridLineType: 'dashed',
|
||||
gridLineDash: [2, 2]
|
||||
},
|
||||
y: {
|
||||
min: 0,
|
||||
num: 6,
|
||||
max: 500
|
||||
},
|
||||
labelLine: {
|
||||
data: ['同期', '环期'],
|
||||
type: 'rectangle'
|
||||
},
|
||||
radius: 4
|
||||
},
|
||||
|
||||
colors: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
</style>
|
@ -1,228 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<border-box-7 class="chart-item" :reverse="true">
|
||||
<polyline-chart :data="polylineChartData1" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Polyline-chart</div>
|
||||
|
||||
<highlight-code>
|
||||
<polyline-chart :data="data" :colors="colors" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 折线图与柱状图折线部分相似
|
||||
data: [
|
||||
{
|
||||
data: [32, 30, 55, 24, 33, 25],
|
||||
lineColor: '#3de7c9'
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳']
|
||||
},
|
||||
showValueText: true,
|
||||
// 非必需 数值展示位置偏移量
|
||||
valueTextOffset: [10, -5]
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<polyline-chart :data="polylineChartData2" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Polyline-chart</div>
|
||||
|
||||
<highlight-code>
|
||||
<polyline-chart :data="data" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
data: [
|
||||
99.81, 99.42, 99.56, 99.23, 99.62,
|
||||
99.36, 99.56, '', 99.81, 99.56, ...
|
||||
],
|
||||
lineType: 'dashed',
|
||||
lineDash: [2, 2],
|
||||
lineColor: '#277dfb',
|
||||
pointColor: '#3de7c9',
|
||||
fillColor: ['rgba(40, 125, 252, 0.3)', 'rgba(40, 125, 252, 0)']
|
||||
},
|
||||
{
|
||||
data: [
|
||||
97.81, 97.42, 97.56, 97.23, 97.62,
|
||||
97.36, 97.56, '', 97.81, 97.56, ...
|
||||
],
|
||||
fillColor: ['rgba(0, 219, 149, 0.3)', 'rgba(0, 219, 149, 0)'],
|
||||
type: 'smoothline'
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: [
|
||||
'10/01', '', '10/03', '', '10/05', '',
|
||||
'10/07', '', '10/09', '', '10/11', '', ...
|
||||
]
|
||||
},
|
||||
y: {
|
||||
min: 96,
|
||||
max: 100,
|
||||
// 数据精度 数据最大最小差值较小时 建议设置精度
|
||||
fixed: 2,
|
||||
num: 10,
|
||||
unit: '%'
|
||||
}
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item" :reverse="true">
|
||||
<polyline-chart :data="polylineChartData3" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Polyline-chart</div>
|
||||
|
||||
<highlight-code>
|
||||
<polyline-chart :data="data" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
data: [2, 2.5, 3, 6, 3, 2.5, 2],
|
||||
fillColor: ['rgba(255, 38, 214, 0.5)', 'rgba(40, 82, 255, 0.1)']
|
||||
},
|
||||
{
|
||||
data: [3, 2, 4, 5, 4, 2, 3],
|
||||
type: 'smoothline'
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: ['10/01', '10/02', '10/03', '10/04', '10/05', '10/06', '10/07']
|
||||
},
|
||||
// 非必需 不贴合坐标轴绘制
|
||||
boundaryGap: true
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<div id="point-chart" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PolylineChartDemo',
|
||||
data () {
|
||||
return {
|
||||
polylineChartData1: {
|
||||
data: [
|
||||
{
|
||||
data: [32, 30, 55, 24, 33, 25],
|
||||
lineColor: '#3de7c9'
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳']
|
||||
},
|
||||
y: {
|
||||
min: 0,
|
||||
max: 100
|
||||
},
|
||||
labelLine: {
|
||||
data: ['车流量'],
|
||||
color: ['#3de7c9'],
|
||||
type: 'rectangle'
|
||||
},
|
||||
showValueText: true,
|
||||
valueTextOffset: [10, -5]
|
||||
},
|
||||
|
||||
polylineChartData2: {
|
||||
data: [
|
||||
{
|
||||
data: [
|
||||
99.81, 99.42, 99.56, 99.23, 99.62,
|
||||
99.36, 99.56, '', 99.81, 99.56,
|
||||
99.42, 99.56, '', '', 99.36,
|
||||
99.42, '', 99.56, '', '',
|
||||
99.56, 99.23, 99.62
|
||||
],
|
||||
lineType: 'dashed',
|
||||
lineDash: [2, 2],
|
||||
lineColor: '#277dfb',
|
||||
pointColor: '#3de7c9',
|
||||
fillColor: ['rgba(40, 125, 252, 0.3)', 'rgba(40, 125, 252, 0)']
|
||||
},
|
||||
{
|
||||
data: [
|
||||
97.81, 97.42, 97.56, 97.23, 97.62,
|
||||
97.36, 97.56, '', 97.81, 97.56,
|
||||
97.42, 97.56, '', '', 97.36,
|
||||
97.42, '', 97.56, '', '',
|
||||
97.56, 97.23, 97.62
|
||||
],
|
||||
fillColor: ['rgba(0, 219, 149, 0.3)', 'rgba(0, 219, 149, 0)'],
|
||||
type: 'smoothline'
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: [
|
||||
'10/01', '', '10/03', '', '10/05', '',
|
||||
'10/07', '', '10/09', '', '10/11', '',
|
||||
'10/13', '', '10/15', '', '10/17', '',
|
||||
'10/19', '', '10/21', '', '10/23'
|
||||
]
|
||||
},
|
||||
y: {
|
||||
min: 96,
|
||||
max: 100,
|
||||
fixed: 2,
|
||||
num: 10,
|
||||
unit: '%'
|
||||
},
|
||||
labelLine: {
|
||||
data: ['同期', '环期'],
|
||||
color: ['#275afe', '#3de7c9'],
|
||||
type: 'rectangle'
|
||||
}
|
||||
},
|
||||
|
||||
polylineChartData3: {
|
||||
data: [
|
||||
{
|
||||
data: [2, 2.5, 3, 6, 3, 2.5, 2],
|
||||
fillColor: ['rgba(255, 38, 214, 0.5)', 'rgba(40, 82, 255, 0.1)']
|
||||
},
|
||||
{
|
||||
data: [3, 2, 4, 5, 4, 2, 3],
|
||||
type: 'smoothline'
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: ['10/01', '10/02', '10/03', '10/04', '10/05', '10/06', '10/07']
|
||||
},
|
||||
labelLine: {
|
||||
data: ['同期', '环期'],
|
||||
color: ['#ff2db8', '#3de7c9'],
|
||||
type: 'rectangle'
|
||||
},
|
||||
color: ['#00baff', '#3de7c9', '#ffc53d', '#342432'],
|
||||
boundaryGap: true
|
||||
},
|
||||
|
||||
colors: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
</style>
|
@ -1,251 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<border-box-7 class="chart-item">
|
||||
<radar-chart :data="radarChartData1" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Radar-Chart</div>
|
||||
<highlight-code>
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
data: [450, 50, 450, 50, 450, 50] // 必须
|
||||
},
|
||||
{
|
||||
data: [50, 450, 50, 450, 50, 450]
|
||||
}, ...
|
||||
],
|
||||
label: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳'] // 必须
|
||||
},
|
||||
// 非必须 不配置该项则不绘制底部label
|
||||
labelLine: {
|
||||
data: ['同期', '环期']
|
||||
}
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<radar-chart :data="radarChartData2" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Radar-Chart</div>
|
||||
<highlight-code>
|
||||
<radar-chart :data="data" :colors="colors" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
data: [450, 50, 450, 50, 450, 50],
|
||||
dashed: true // 非必须 为真时绘制虚线
|
||||
},
|
||||
{
|
||||
data: [50, 450, 50, 450, 50, 450],
|
||||
lineColor: '#9cf4df', // 非必须 可配置改数据线条颜色
|
||||
fillColor: 'rgba(238, 233, 108, 0.5)' // 非必须 可配置改数据填充颜色
|
||||
}
|
||||
],
|
||||
label: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳'],
|
||||
color: 'colors', // 非必须 可配置文字颜色
|
||||
fontSize: 10 // 非必须 可配置文字大小
|
||||
},
|
||||
labelLine: ['同期', '环期'],
|
||||
rayLineType: 'dashed', // 非必须 设置径向射线为虚线
|
||||
rayLineColor: 'colors', // 非必须 设置径向射线颜色
|
||||
ringNum: 5, // 非必填 设置环线个数
|
||||
ringType: 'polyline', // 非必须 设置环线为折线
|
||||
ringFillType: 'cover', // 非必须 设置环线填充颜色类型为cover
|
||||
ringFillColor: ['rgba(61, 231, 201, 0.3)', 'rgba(61, 231, 201, 0.1)'], // 非必须 设置环线填充色
|
||||
ringLineType: 'line', // 非必须 设置环线线条为实线
|
||||
ringLineColor: 'rgba(156, 244, 233, 0.2)', // 非必须 设置环线线条颜色
|
||||
rayLineOffset: Math.PI * -1.5, // 非必须 设置雷达图旋转偏移
|
||||
radius: 0.8, // 非必须 设置雷达图最大环线半径
|
||||
max: 550 // 非必须 设置雷达图数据最大值
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<radar-chart :data="radarChartData3" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Radar-Chart</div>
|
||||
<highlight-code>
|
||||
<radar-chart :data="data" :colors="colors" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 相同配置不再赘述
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
data: [....],
|
||||
// 非必须 设置该列数据值标签颜色为继承
|
||||
valueTextColor: 'inherit'
|
||||
}
|
||||
],
|
||||
ringFillColor: ['rgba(61, 231, 201, 0.1)'],
|
||||
ringFillType: 'mulCover', // 非必须 设置环线填充颜色类型为mulCover
|
||||
showValueText: true
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="chart-item">
|
||||
<radar-chart :data="radarChartData4" :colors="colors" class="chart" />
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Radar-Chart</div>
|
||||
<highlight-code>
|
||||
<radar-chart :data="data" :colors="colors" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 相同配置不再赘述
|
||||
data: {
|
||||
ringFillColor: ['rgba(61, 231, 201, 0.1)'],
|
||||
ringFillType: 'ring', // 非必须 设置环线填充颜色类型为ring
|
||||
}
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'RadarChartDemo',
|
||||
data () {
|
||||
return {
|
||||
radarChartData1: {
|
||||
data: [
|
||||
{
|
||||
data: [450, 50, 450, 50, 450, 50]
|
||||
},
|
||||
{
|
||||
data: [50, 450, 50, 450, 50, 450]
|
||||
}
|
||||
],
|
||||
label: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳']
|
||||
},
|
||||
labelLine: {
|
||||
data: ['同期', '环期']
|
||||
}
|
||||
},
|
||||
|
||||
radarChartData2: {
|
||||
data: [
|
||||
{
|
||||
data: [450, 50, 450, 50, 450, 50],
|
||||
dashed: true
|
||||
},
|
||||
{
|
||||
data: [50, 450, 50, 450, 50, 450],
|
||||
lineColor: '#9cf4df',
|
||||
fillColor: 'rgba(238, 233, 108, 0.5)'
|
||||
}
|
||||
],
|
||||
label: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳'],
|
||||
color: 'colors',
|
||||
fontSize: 10
|
||||
},
|
||||
labelLine: {
|
||||
data: ['同期', '环期']
|
||||
},
|
||||
rayLineType: 'dashed',
|
||||
rayLineColor: 'colors',
|
||||
ringNum: 5,
|
||||
ringType: 'polyline',
|
||||
ringFillType: 'cover',
|
||||
ringFillColor: ['rgba(61, 231, 201, 0.3)', 'rgba(61, 231, 201, 0.1)'],
|
||||
ringLineType: 'line',
|
||||
ringLineColor: 'rgba(156, 244, 233, 0.2)',
|
||||
rayLineOffset: Math.PI * -1.5,
|
||||
radius: 0.8,
|
||||
max: 550
|
||||
},
|
||||
|
||||
radarChartData3: {
|
||||
data: [
|
||||
{
|
||||
data: [450, 50, 450, 50, 450, 50],
|
||||
valueTextColor: 'inherit'
|
||||
},
|
||||
{
|
||||
data: [50, 450, 50, 450, 50, 450],
|
||||
valueTextColor: 'inherit'
|
||||
}
|
||||
],
|
||||
label: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳'],
|
||||
color: 'colors',
|
||||
fontSize: 10
|
||||
},
|
||||
labelLine: {
|
||||
data: ['同期', '环期']
|
||||
},
|
||||
rayLineType: 'dashed',
|
||||
rayLineColor: 'colors',
|
||||
ringNum: 5,
|
||||
ringType: 'polyline',
|
||||
ringFillType: 'mulCover',
|
||||
ringFillColor: ['rgba(61, 231, 201, 0.1)'],
|
||||
ringLineType: 'line',
|
||||
ringLineColor: 'rgba(156, 244, 233, 0.2)',
|
||||
rayLineOffset: Math.PI * -1.5,
|
||||
radius: 0.8,
|
||||
max: 550,
|
||||
showValueText: true
|
||||
},
|
||||
|
||||
radarChartData4: {
|
||||
data: [
|
||||
{
|
||||
data: [450, 50, 450, 50, 450, 50]
|
||||
},
|
||||
{
|
||||
data: [50, 450, 50, 450, 50, 450]
|
||||
}
|
||||
],
|
||||
label: {
|
||||
data: ['西峡', '周口', '南阳', '驻马店', '郑州', '洛阳'],
|
||||
color: 'colors',
|
||||
fontSize: 10
|
||||
},
|
||||
labelLine: {
|
||||
data: ['同期', '环期']
|
||||
},
|
||||
rayLineType: 'dashed',
|
||||
rayLineColor: 'colors',
|
||||
ringNum: 5,
|
||||
ringType: 'polyline',
|
||||
ringFillType: 'ring',
|
||||
ringFillColor: ['rgba(61, 231, 201, 0.3)', 'rgba(61, 231, 201, 0.1)'],
|
||||
ringLineType: 'line',
|
||||
ringLineColor: 'rgba(156, 244, 233, 0.2)',
|
||||
rayLineOffset: Math.PI * -1.5,
|
||||
radius: 0.8,
|
||||
max: 550
|
||||
},
|
||||
|
||||
colors: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
</style>
|
@ -1,152 +0,0 @@
|
||||
<template>
|
||||
<div id="decoration">
|
||||
<border-box-7 class="decoration-container">
|
||||
<decoration-1 class="decoration d1 center" />
|
||||
|
||||
<div class="title">Decoration-1</div>
|
||||
<highlight-code>
|
||||
<decoration-1 />
|
||||
</highlight-code>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="decoration-container">
|
||||
<decoration-2 class="decoration d2 center" />
|
||||
<div class="title">Decoration-2</div>
|
||||
<highlight-code>
|
||||
<decoration-2 />
|
||||
</highlight-code>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="decoration-container">
|
||||
<decoration-2 class="decoration d2r center" :reverse="true" />
|
||||
<div class="title">Decoration-2(reverse)</div>
|
||||
<highlight-code>
|
||||
<decoration-2 :reverse="true" />
|
||||
</highlight-code>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="decoration-container">
|
||||
<decoration-3 class="decoration d3 center" />
|
||||
<div class="title">Decoration-3</div>
|
||||
<highlight-code>
|
||||
<decoration-3 />
|
||||
</highlight-code>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="decoration-container">
|
||||
<decoration-4 class="decoration d4 center" />
|
||||
<div class="title">Decoration-4</div>
|
||||
<highlight-code>
|
||||
<decoration-4 />
|
||||
</highlight-code>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="decoration-container">
|
||||
<decoration-4 class="decoration d4r center" :reverse="true" />
|
||||
<div class="title">Decoration-4(reverse)</div>
|
||||
<highlight-code>
|
||||
<decoration-4 :reverse="true" />
|
||||
</highlight-code>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="decoration-container">
|
||||
<decoration-5 class="decoration d4r center" />
|
||||
<div class="title">Decoration-5</div>
|
||||
<highlight-code>
|
||||
<decoration-5 />
|
||||
</highlight-code>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="decoration-container">
|
||||
<decoration-6 class="decoration d4r center" />
|
||||
<div class="title">Decoration-6</div>
|
||||
<highlight-code>
|
||||
<decoration-6 />
|
||||
</highlight-code>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="decoration-container">
|
||||
<decoration-7 class="decoration d4r center">Decoration</decoration-7>
|
||||
<div class="title">Decoration-7</div>
|
||||
<highlight-code>
|
||||
<decoration-7>Decoration<dtn-7 />
|
||||
</highlight-code>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="decoration-container">
|
||||
<loading class="decoration center" />
|
||||
<div class="title">Loading</div>
|
||||
<highlight-code>
|
||||
<loading />
|
||||
</highlight-code>
|
||||
</border-box-7>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DecorationDemo'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
#decoration {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
padding-bottom: 100px;
|
||||
|
||||
.decoration-container {
|
||||
position: relative;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
margin: 0 20px;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.title {
|
||||
text-indent: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.decoration {
|
||||
position: absolute;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.center {
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.d1 {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.d2 {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.d2r {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.d3 {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.d4 {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.d4r {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,53 +0,0 @@
|
||||
<template>
|
||||
<div id="datav-document">
|
||||
<div class="document">
|
||||
<div class="title">介绍</div>
|
||||
|
||||
<div class="text-info">本组件库基于Vue, 用构建大屏数据展示(图表类)</div>
|
||||
<div class="text-info">类似于echarts, 但是消耗资源更小, 更轻量, 易于使用</div>
|
||||
|
||||
<div class="title">使用</div>
|
||||
|
||||
<div class="text-info">你需要将DataV文件夹复制至你的项目内</div>
|
||||
<div class="text-info">并在main.js中引入使用</div>
|
||||
|
||||
<highlight-code>
|
||||
// main.js
|
||||
import dataV from './DataV/index.js'
|
||||
|
||||
Vue.use(dataV)
|
||||
|
||||
// 可以直接在Views文件夹下的dataView页面直接编写页面
|
||||
// dataView页面已做全屏缩放处理 routerPath: #/datav/view
|
||||
</highlight-code>
|
||||
|
||||
<div class="text-info">组件具体用法见示例</div>
|
||||
<div class="text-info"><a href="https://github.com/jiaming743/DataV" target="_BLANK">GitHub</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'DatavDocument'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
#datav-document {
|
||||
font-size: 15px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
|
||||
a {
|
||||
color: #0084ff;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:visited {
|
||||
color: #0084ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,149 +0,0 @@
|
||||
<template>
|
||||
<div class="demo" ref="demo">
|
||||
<div class="menu-bar">
|
||||
<div :class="`menu-item ${activeIndex === index && 'active'}`"
|
||||
v-for="(item, index) in menuData"
|
||||
:key="item.title"
|
||||
@click="$router.push({ name: item.routerName }) & (activeIndex = index)">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="router-container">
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Demo',
|
||||
data () {
|
||||
return {
|
||||
activeIndex: 0,
|
||||
|
||||
menuData: [
|
||||
{
|
||||
title: 'Document',
|
||||
routerName: 'document'
|
||||
},
|
||||
{
|
||||
title: 'Border-Box',
|
||||
routerName: 'borderBox'
|
||||
},
|
||||
{
|
||||
title: 'Decoration',
|
||||
routerName: 'decoration'
|
||||
},
|
||||
{
|
||||
title: 'Chart',
|
||||
routerName: 'chart'
|
||||
},
|
||||
{
|
||||
title: 'Other',
|
||||
routerName: 'other'
|
||||
},
|
||||
{
|
||||
title: 'Show',
|
||||
routerName: 'show'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
scaleScreen () {
|
||||
const { $refs } = this
|
||||
|
||||
const demoDom = $refs['demo']
|
||||
|
||||
const { height } = screen
|
||||
const bdWidth = document.body.clientWidth
|
||||
const bdHeight = document.body.clientHeight
|
||||
|
||||
if (bdWidth < 1500) {
|
||||
const scale = bdWidth / 1500
|
||||
demoDom.style.transform = `scale(${scale})`
|
||||
demoDom.style.height = bdHeight * (height / bdHeight) * (1 / scale) + 'px'
|
||||
}
|
||||
},
|
||||
bindReSizeEventHandler () {
|
||||
const { debounce, scaleScreen } = this
|
||||
|
||||
if (!debounce) return
|
||||
|
||||
window.addEventListener('resize', debounce(100, scaleScreen))
|
||||
},
|
||||
initActiveIndex () {
|
||||
const { $route: { name }, menuData } = this
|
||||
|
||||
this.activeIndex = menuData.findIndex(({ routerName }) => routerName === name)
|
||||
}
|
||||
},
|
||||
created () {
|
||||
const { initActiveIndex } = this
|
||||
|
||||
initActiveIndex()
|
||||
},
|
||||
mounted () {
|
||||
const { scaleScreen, bindReSizeEventHandler } = this
|
||||
|
||||
scaleScreen()
|
||||
|
||||
bindReSizeEventHandler()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.demo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('../../assets/img/bg.png');
|
||||
background-size: 100%;
|
||||
color: #fff;
|
||||
min-width: 1500px;
|
||||
transform-origin: left top;
|
||||
|
||||
.menu-bar {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
margin: 10px 0px;
|
||||
}
|
||||
|
||||
.active {
|
||||
border-bottom: 3px solid #0084ff;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
margin: 0px 20px;
|
||||
cursor: pointer;
|
||||
z-index: 9;
|
||||
|
||||
&:hover {
|
||||
border-bottom: 3px solid #0084ff;
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: #0084ff;
|
||||
}
|
||||
}
|
||||
|
||||
.router-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
padding: 70px 100px 0px 100px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,295 +0,0 @@
|
||||
<template>
|
||||
<div id="other">
|
||||
<border-box-7 class="other-item">
|
||||
<div class="component">
|
||||
<scroll-board :index="true" :data="scrollBoardData1" :columnWidth="[50, 50, 50]" :textAlign="['center', 'center']" />
|
||||
</div>
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Water-Level-Pond</div>
|
||||
|
||||
<highlight-code>
|
||||
<scroll-board :data="data" :index="true" :columnWidth="columnWidth" :textAlign="textAlign" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
data: { // data内容可以是html标签 内容由v-html渲染
|
||||
data: [ // 必须 每行数据的数组长度应保持一致
|
||||
['张三', '男', '这里是地址'],
|
||||
['李四', '女', '这里是地址'],
|
||||
['王五', '男', '这里是地址'],
|
||||
['赵六', '女', '这里是地址'],
|
||||
['钱七', '男', '这里是地址'],
|
||||
['孙八', '女', '这里是地址'],
|
||||
['杨九', '男', '这里是地址'],
|
||||
['吴十', '女', '这里是地址']
|
||||
]
|
||||
}
|
||||
// 非必须 设置每一栏的宽度 允许插入空位 空位均分宽度
|
||||
columnWidth: [50, 50, 50]
|
||||
// 非必须 设置每一栏的对齐方式 允许插入空位 默认居左
|
||||
textAlign: ['center', 'center']
|
||||
// index 非必须 属性为真时 自动添加序号
|
||||
// rowNum 非必须 可以设置展示行数
|
||||
// oddBG 非必须 可以设置奇数行背景色
|
||||
// evenBG 非必须 可以设置偶数行背景色
|
||||
// titleBG 非必须 可设置表头背景色
|
||||
// carousel 非必须 设置为page 滚动时整页滚动
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="other-item">
|
||||
<div class="component">
|
||||
<scroll-board :data="scrollBoardData2" carousel="page" :columnWidth="[50, 50]" :textAlign="['center', 'center']" />
|
||||
</div>
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Water-Level-Pond</div>
|
||||
|
||||
<highlight-code>
|
||||
<scroll-board :data="data" carousel="page" :columnWidth="columnWidth" :textAlign="textAlign" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
data: {
|
||||
data: [
|
||||
['张三', '男', '这里是地址'],
|
||||
['李四', '女', '这里是地址'],
|
||||
['王五', '男', '这里是地址'],
|
||||
['赵六', '女', '这里是地址'],
|
||||
['钱七', '男', '这里是地址'],
|
||||
['孙八', '女', '这里是地址'],
|
||||
['杨九', '男', '这里是地址'],
|
||||
['吴十', '女', '这里是地址']
|
||||
],
|
||||
// 非必须 添加此项自动生成表头
|
||||
title: ['姓名', '性别', '地址']
|
||||
}
|
||||
columnWidth: [50, 50]
|
||||
textAlign: ['center', 'center']
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="other-item">
|
||||
<div class="component">
|
||||
<water-level-pond :level="[60, 40]" />
|
||||
</div>
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Water-Level-Pond</div>
|
||||
|
||||
<highlight-code>
|
||||
<water-level-pond :level="[60, 40]" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// level必须为数组
|
||||
// 可绑定colors属性 非必须 未配置该项自动使用默认色
|
||||
// 当colors属性为数组时 波浪自动应用渐变色
|
||||
// noGradient为true时可关闭波浪渐变色效果
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="other-item">
|
||||
<div class="component">
|
||||
<water-level-pond :level="[60, 40]" type="rect" :waveNum="2" :waveHeight="0.3" />
|
||||
</div>
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Water-Level-Pond</div>
|
||||
|
||||
<highlight-code>
|
||||
<water-level-pond :level="[60, 40]" type="rect" :waveNum="2" :waveHeight="0.3" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 矩形样式
|
||||
// waveNum 可设置波峰个数
|
||||
// waveHeight 可设置波峰高度
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="other-item">
|
||||
<div class="component">
|
||||
<water-level-pond :level="[60, 40]" type="roundRect" borderColor="rgba(45, 219, 216, 0.5)" />
|
||||
</div>
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Water-Level-Pond</div>
|
||||
|
||||
<highlight-code>
|
||||
<water-level-pond :level="[60, 40]" type="roundRect" borderColor="rgba(45, 219, 216, 0.5)" />
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 圆角矩形样式
|
||||
// 可特殊设置边框颜色 文字与边框颜色同步
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="other-item">
|
||||
<div class="component">
|
||||
<percent-pond :percent="66" />
|
||||
</div>
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Percent-Pond</div>
|
||||
|
||||
<highlight-code>
|
||||
<percent-pond :percent="66" />
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="other-item">
|
||||
<div class="component">
|
||||
<percent-arc :percent="66" :ringLineWidth="10" :arcLineWidth="20" arcType="round">66</percent-arc>
|
||||
</div>
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Percent-Arc</div>
|
||||
|
||||
<highlight-code>
|
||||
<percent-arc :percent="66" :ringLineWidth="10" :arcLineWidth="20" arcType="round">66<percent-arc/>
|
||||
</highlight-code>
|
||||
|
||||
<highlight-code>
|
||||
// 内置slot 可以置入任意元素
|
||||
// percent 必须 设置弧度程度
|
||||
// arcType 非必须 设置是否为圆角弧形 round | butt
|
||||
// raidus 非必须 设置环半径
|
||||
// ringLineWidth 非必须 设置环线宽度
|
||||
// arcLineWidth 非必须 设置弧线宽度
|
||||
// ringColor 非必须 设置环线颜色 只能设置一种颜色
|
||||
// arcColor 非必须 设置弧线颜色 可以设置多种 多种自动渐变
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="other-item">
|
||||
<div class="component">
|
||||
<percent-arc :percent="66" ringColor="#c7166f" :arcColor="['#2755fe', '#ff12cb']">66</percent-arc>
|
||||
</div>
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Percent-Arc</div>
|
||||
|
||||
<highlight-code>
|
||||
<percent-arc :percent="66" ringColor="#c7166f" :arcColor="['#2755fe', '#ff12cb']">66<percent-arc/>
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
|
||||
<border-box-7 class="other-item">
|
||||
<div class="component">
|
||||
<number-show :number="1399" />
|
||||
</div>
|
||||
|
||||
<div class="config-info">
|
||||
<div class="title">Number-Show</div>
|
||||
|
||||
<highlight-code>
|
||||
<number-show :number="1399" />
|
||||
</highlight-code>
|
||||
</div>
|
||||
</border-box-7>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Other',
|
||||
data () {
|
||||
return {
|
||||
scrollBoardData1: {
|
||||
data: [
|
||||
['张三', '男', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['李四', '女', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['王五', '男', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['赵六', '女', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['钱七', '男', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['孙八', '女', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['杨九', '男', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['吴十', '女', '这里是地址这里是地址这里是地址这里是地址']
|
||||
]
|
||||
},
|
||||
scrollBoardData2: {
|
||||
data: [
|
||||
['张三', '男', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['李四', '女', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['王五', '男', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['赵六', '女', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['钱七', '男', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['孙八', '女', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['杨九', '男', '这里是地址这里是地址这里是地址这里是地址'],
|
||||
['吴十', '女', '这里是地址这里是地址这里是地址这里是地址']
|
||||
],
|
||||
title: ['姓名', '性别', '地址']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
#other {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.other-item {
|
||||
width: 80%;
|
||||
margin-left: 20%;
|
||||
min-height: 300px;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.component {
|
||||
width: 400px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.config-info {
|
||||
padding: 0px 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.highlight-code {
|
||||
margin: -30px 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-board {
|
||||
width: 350px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.water-level-pond {
|
||||
width: 150px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.percent-pond {
|
||||
width: 300px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.percent-arc {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
font-size: 50px;
|
||||
color: aqua;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,56 +0,0 @@
|
||||
<template>
|
||||
<div id="show">
|
||||
<border-box-7 class="show-item" v-for="show in showData" :key="show.title">
|
||||
<a :href="show.href" target="_BLANK">{{ show.title }}</a>
|
||||
</border-box-7>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Show',
|
||||
data () {
|
||||
return {
|
||||
showData: [
|
||||
{
|
||||
title: '运维管理台',
|
||||
href: 'http://datav.jiaminghi.com/demo/manage-desk'
|
||||
},
|
||||
{
|
||||
title: '运维电子档案',
|
||||
href: 'http://datav.jiaminghi.com/demo/electronic-file'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
#show {
|
||||
|
||||
.show-item {
|
||||
width: 60%;
|
||||
height: 300px;
|
||||
margin-left: 20%;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
font-size: 100px;
|
||||
line-height: 300px;
|
||||
}
|
||||
|
||||
a {
|
||||
position: relative;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
text-shadow: 0 0 10px gray;
|
||||
z-index: 9;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:visited {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 7.7 KiB |
@ -1,688 +0,0 @@
|
||||
<template>
|
||||
<div id="manage-desk">
|
||||
<div class="header">
|
||||
<div class="left">技术支持:<a :href="technicalSupport" target="_BLANK">{{ technicalSupport }}</a></div>
|
||||
<div class="middle">{{ topMiddleTitle }}</div>
|
||||
<border-box-2 class="right">
|
||||
设备档案馆
|
||||
</border-box-2>
|
||||
</div>
|
||||
|
||||
<border-box-1 class="content">
|
||||
<div class="top">
|
||||
<div class="top-left">
|
||||
<div class="top-left-title-1">
|
||||
当月维修任务量
|
||||
<decoration-3 />
|
||||
</div>
|
||||
|
||||
<div class="top-left-title-2">
|
||||
<decoration-3 />
|
||||
运维人均工作量
|
||||
</div>
|
||||
|
||||
<border-box-5 class="top-left-box-1">
|
||||
<div class="tlb-text">
|
||||
<div>{{ chart1Data.monthSum }}</div>
|
||||
<div class="small-text">{{ chart1Data.lastMonthSum }}</div>
|
||||
<div class="small-text">{{ chart1Data.lastYearMonthSum }}</div>
|
||||
</div>
|
||||
</border-box-5>
|
||||
|
||||
<border-box-5 class="top-left-box-2" :reverse="true">
|
||||
<div class="tlb-text">
|
||||
<div>{{ chart1Data.personDayAvg }}</div>
|
||||
<div class="small-text">{{ chart1Data.personLastMonthDayAvg }}</div>
|
||||
<div class="small-text">{{ chart1Data.personLastYearMonthDayAvg }}</div>
|
||||
</div>
|
||||
</border-box-5>
|
||||
</div>
|
||||
|
||||
<div class="top-right">
|
||||
<polyline-chart :data="chart2Data">
|
||||
<div class="title-item">
|
||||
设备完好率月趋势
|
||||
<decoration-3 />
|
||||
</div>
|
||||
</polyline-chart>
|
||||
|
||||
<polyline-chart :data="chart3Data">
|
||||
<div class="title-item">
|
||||
设备故障月趋势
|
||||
<decoration-3 />
|
||||
</div>
|
||||
</polyline-chart>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bottom">
|
||||
<border-box-6 class="bottom-left">
|
||||
<decoration-4 class="bottom-left-decoration-1" />
|
||||
<decoration-4 class="bottom-left-decoration-2" />
|
||||
|
||||
<div class="bottom-left-item">
|
||||
<div class="bli-title">机电设备完好率</div>
|
||||
<div class="bli-value left-value">{{ chart4Data.deviceNormalPercent }}</div>
|
||||
<arc-ring-chart class="bli-chart" :data="chart4Data.data" />
|
||||
</div>
|
||||
<div class="bottom-left-item">
|
||||
<div class="bli-title">任务维修平均用时</div>
|
||||
<div class="bli-value right-value">{{ chart5Data.avgTime}}</div>
|
||||
<concentric-arc-chart class="bli-chart" :data="chart5Data.data" />
|
||||
</div>
|
||||
</border-box-6>
|
||||
|
||||
<div class="bottom-right">
|
||||
<border-box-6 class="bottom-right-item">
|
||||
<div class="title-item">
|
||||
<img src="./img/1.png" />人员贡献排行榜
|
||||
</div>
|
||||
|
||||
<scroll-board :data="chart6Data" />
|
||||
</border-box-6>
|
||||
|
||||
<border-box-6 class="bottom-right-item">
|
||||
<div class="title-item">
|
||||
<img src="./img/2.png" />故障设备排行榜
|
||||
</div>
|
||||
|
||||
<scroll-board :data="chart7Data" />
|
||||
</border-box-6>
|
||||
|
||||
<border-box-6 class="bottom-right-item">
|
||||
<div class="title-item">
|
||||
<img src="./img/3.png" />常见故障排行榜
|
||||
</div>
|
||||
|
||||
<scroll-board :data="bottomRightScrollBorad3Data" />
|
||||
</border-box-6>
|
||||
|
||||
<border-box-6 class="bottom-right-item">
|
||||
<div class="title-item">
|
||||
<img src="./img/4.png" />故障位置排行榜
|
||||
</div>
|
||||
|
||||
<scroll-board :data="chart9Data" />
|
||||
</border-box-6>
|
||||
</div>
|
||||
</div>
|
||||
</border-box-1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ManageDesk',
|
||||
data () {
|
||||
return {
|
||||
technicalSupport: 'https://github.com/jiaming743/DataV',
|
||||
topMiddleTitle: 'Demo-机电运维管理台',
|
||||
|
||||
// 上部左边卡片数据
|
||||
chart1Data: {
|
||||
monthSum: 0,
|
||||
lastMonthSum: 81,
|
||||
lastYearMonthSum: 0,
|
||||
personDayAvg: 0.1,
|
||||
personLastMonthDayAvg: 0.3,
|
||||
personLastYearMonthDayAvg: 0
|
||||
},
|
||||
|
||||
// 上部右边第一个图表数据
|
||||
chart2Data: {
|
||||
data: [
|
||||
{
|
||||
data: [
|
||||
99.81, 99.42, 99.56, 99.23, 99.62,
|
||||
99.36, 99.56, '', 99.81, 99.56,
|
||||
99.42, 99.56, '', '', 99.36,
|
||||
99.42, '', 99.56, '', '',
|
||||
99.56, 99.23, 99.62
|
||||
],
|
||||
fillColor: ['rgba(0, 186, 255, 0.3)', 'rgba(0, 186, 255, 0)'],
|
||||
pointColor: '#00db95',
|
||||
type: 'smoothline'
|
||||
}
|
||||
],
|
||||
color: ['#00baff'],
|
||||
x: {
|
||||
data: [
|
||||
'10/01', '', '10/03', '', '10/05', '',
|
||||
'10/07', '', '10/09', '', '10/11', '',
|
||||
'10/13', '', '10/15', '', '10/17', '',
|
||||
'10/19', '', '10/21', '', '10/23'
|
||||
]
|
||||
},
|
||||
y: {
|
||||
min: 96,
|
||||
max: 100,
|
||||
fixed: 2,
|
||||
num: 10,
|
||||
unit: '%'
|
||||
},
|
||||
labelLine: ['设备完好率']
|
||||
},
|
||||
|
||||
// 上部右边第二个图表数据
|
||||
chart3Data: {
|
||||
data: [
|
||||
{
|
||||
data: [2, 3, 6, 5, 4, 5, 2],
|
||||
type: 'column',
|
||||
columnColor:['rgba(0, 186, 255, 0.5)', 'rgba(0, 186, 255, 0.1)']
|
||||
},
|
||||
{
|
||||
data: [1, 2, 4, 4, 5, 4, 1],
|
||||
type: 'smoothline',
|
||||
dashed: true,
|
||||
fillColor:['rgba(61, 231, 201, 0.5)', 'rgba(61, 231, 201, 0.1)']
|
||||
},
|
||||
{
|
||||
data: [0.5, 1, 3, 3, 4, 3, 0.5],
|
||||
fillColor:['rgba(254, 217, 78, 0.5)', 'rgba(254, 217, 78, 0.1)']
|
||||
},
|
||||
{
|
||||
data: [2, 3, 6, 5, 6, 5, 2]
|
||||
}
|
||||
],
|
||||
x: {
|
||||
data: [
|
||||
'', '10/07',
|
||||
'', '10/14',
|
||||
'', '10/21', ''
|
||||
]
|
||||
},
|
||||
y: {
|
||||
max: 8,
|
||||
min: 0,
|
||||
unit: '单位'
|
||||
},
|
||||
labelLine: ['收费系统', '收费系统', '监控系统', '供配电系统'],
|
||||
color: ['#00baff', '#3de7c9', '#f5d94e', '#ff5ca9'],
|
||||
boundaryGap: true
|
||||
},
|
||||
|
||||
// 底部左边第一个图表数据
|
||||
chart4Data: {
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
value: 19,
|
||||
title: '监控系统'
|
||||
},
|
||||
{
|
||||
value: 16,
|
||||
title: '收费系统'
|
||||
},
|
||||
{
|
||||
value: 24,
|
||||
title: '通信系统'
|
||||
},
|
||||
{
|
||||
value: 14,
|
||||
title: '供配电系统'
|
||||
},
|
||||
{
|
||||
value: 27,
|
||||
title: '其他'
|
||||
}
|
||||
],
|
||||
color: ['#00c0ff', '#3de7c9', '#fff']
|
||||
},
|
||||
deviceNormalPercent: 99.01
|
||||
},
|
||||
|
||||
// 底部左边第二个图表数据
|
||||
chart5Data: {
|
||||
data: {
|
||||
data: [
|
||||
{
|
||||
value: 0.38,
|
||||
title: '8小时以内'
|
||||
},
|
||||
{
|
||||
value: 0.57,
|
||||
title: '24小时以内'
|
||||
},
|
||||
{
|
||||
value: 0.7,
|
||||
title: '48小时以内'
|
||||
},
|
||||
{
|
||||
value: 0.78,
|
||||
title: '72小时以内'
|
||||
},
|
||||
{
|
||||
value: 0.22,
|
||||
title: '大于72小时'
|
||||
}
|
||||
],
|
||||
color: ['#00c0ff', '#3de7c9'],
|
||||
arcArea: [0.3, 0.7],
|
||||
arcGap: 5,
|
||||
fontSize: 12
|
||||
},
|
||||
avgTime: 55.1
|
||||
},
|
||||
|
||||
// 底部右边第一个滚动榜单数据
|
||||
chart6Data: {
|
||||
data: [
|
||||
{
|
||||
title: '赵亚伟',
|
||||
info: '月累计排除故障: 3起'
|
||||
},
|
||||
{
|
||||
title: '刘川',
|
||||
info: '月累计排除故障: 3起'
|
||||
},
|
||||
{
|
||||
title: '方扛',
|
||||
info: '月累计排除故障: 3起'
|
||||
},
|
||||
{
|
||||
title: '孙鹏飞',
|
||||
info: '月累计排除故障: 3起'
|
||||
},
|
||||
{
|
||||
title: '仲文豪',
|
||||
info: '月累计排除故障: 2起'
|
||||
},
|
||||
{
|
||||
title: '李东洋',
|
||||
info: '月累计排除故障: 2起'
|
||||
},
|
||||
{
|
||||
title: '贾果果',
|
||||
info: '月累计排除故障: 1起'
|
||||
},
|
||||
{
|
||||
title: '魏振正',
|
||||
info: '月累计排除故障: 1起'
|
||||
}
|
||||
],
|
||||
showItemNum: 5
|
||||
},
|
||||
|
||||
// 底部右边第二个滚动榜单数据
|
||||
chart7Data: {
|
||||
data: [
|
||||
{
|
||||
title: '液晶显示器',
|
||||
info: '月累计: 2起'
|
||||
},
|
||||
{
|
||||
title: '车牌识别仪',
|
||||
info: '月累计: 2起'
|
||||
},
|
||||
{
|
||||
title: '自动栏杆机',
|
||||
info: '月累计: 2起'
|
||||
},
|
||||
{
|
||||
title: '称重仪表',
|
||||
info: '月累计: 2起'
|
||||
},
|
||||
{
|
||||
title: '收费键盘',
|
||||
info: '月累计: 2起'
|
||||
}
|
||||
],
|
||||
showItemNum: 5
|
||||
},
|
||||
|
||||
// 底部右边第三个滚动榜单数据
|
||||
bottomRightScrollBorad3Data: {
|
||||
data: [
|
||||
{
|
||||
title: '栏杆机不能抬起',
|
||||
info: '月累计: 5起'
|
||||
},
|
||||
{
|
||||
title: '栏杆机落杆',
|
||||
info: '月累计: 3起'
|
||||
},
|
||||
{
|
||||
title: '光端机故障',
|
||||
info: '月累计: 2起'
|
||||
},
|
||||
{
|
||||
title: '票据打印机',
|
||||
info: '月累计: 2起'
|
||||
},
|
||||
{
|
||||
title: '视频无图像',
|
||||
info: '月累计: 2起'
|
||||
},
|
||||
{
|
||||
title: '视频花屏',
|
||||
info: '月累计: 1起'
|
||||
},
|
||||
{
|
||||
title: '车牌识别仪',
|
||||
info: '月累计: 1起'
|
||||
}
|
||||
],
|
||||
showItemNum: 5
|
||||
},
|
||||
|
||||
// 底部右边第四个滚动榜单数据
|
||||
chart9Data: {
|
||||
data: [
|
||||
{
|
||||
title: '收费广场',
|
||||
info: '发生故障: 3起'
|
||||
},
|
||||
{
|
||||
title: '外场道路',
|
||||
info: '发生故障: 3起'
|
||||
},
|
||||
{
|
||||
title: '运维分中心',
|
||||
info: '发生故障: 3起'
|
||||
},
|
||||
{
|
||||
title: '服务区',
|
||||
info: '发生故障: 3起'
|
||||
},
|
||||
{
|
||||
title: '其他',
|
||||
info: '发生故障: 2起'
|
||||
}
|
||||
],
|
||||
showItemNum: 4
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
#manage-desk {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: #fff;
|
||||
|
||||
.header {
|
||||
position: relative;
|
||||
height: 80px;
|
||||
|
||||
.left, .middle, .right {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.left {
|
||||
left: 35px;
|
||||
bottom: 0px;
|
||||
font-size: 20px;
|
||||
color: rgba(1, 134, 187, 0.91);
|
||||
|
||||
a {
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:visited {
|
||||
color: rgba(1, 134, 187, 0.91);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.middle {
|
||||
font-size: 33px;
|
||||
left: 50%;
|
||||
bottom: 0px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 140px;
|
||||
font-size: 18px;
|
||||
right: 130px;
|
||||
bottom: -20px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
height: calc(~"100% - 80px");
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.top {
|
||||
width: 100%;
|
||||
height: 35%;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 60px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.top-left, .bottom-left {
|
||||
width: 32%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.top-left {
|
||||
position: relative;
|
||||
|
||||
.top-left-title-1, .top-left-title-2 {
|
||||
position: absolute;
|
||||
font-size: 20px;
|
||||
width: 170px;
|
||||
}
|
||||
|
||||
.top-left-title-1 {
|
||||
left: 51%;
|
||||
text-align: right;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.top-left-title-2 {
|
||||
right: 51%;
|
||||
text-align: left;
|
||||
bottom: 20px;
|
||||
}
|
||||
|
||||
.border-box-5 {
|
||||
position: absolute;
|
||||
width: 48%;
|
||||
height: 60%;
|
||||
}
|
||||
|
||||
.tlb-text {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
|
||||
:nth-child(1) {
|
||||
color: #00c0ff;
|
||||
font-size: 48px;
|
||||
font-weight: bold;
|
||||
|
||||
&::after {
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.small-text {
|
||||
font-size: 16px;
|
||||
margin: 10px 0px;
|
||||
|
||||
&::before {
|
||||
margin-right: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
:nth-child(2) {
|
||||
|
||||
&::before {
|
||||
content: '同期';
|
||||
}
|
||||
}
|
||||
|
||||
:nth-child(3) {
|
||||
|
||||
&::before {
|
||||
content: '环期';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.top-left-box-1 {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
|
||||
.tlb-text {
|
||||
left: 40px;
|
||||
}
|
||||
|
||||
.tlb-text :nth-child(1)::after {
|
||||
content: '件'
|
||||
}
|
||||
}
|
||||
|
||||
.top-left-box-2 {
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
|
||||
.tlb-text {
|
||||
right: 40px;
|
||||
}
|
||||
|
||||
.tlb-text :nth-child(1)::after {
|
||||
content: '件 / 日'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.top-right, .bottom-right {
|
||||
flex: 1;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.top-right {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
|
||||
.polyline-chart {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.title-item {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
width: 180px;
|
||||
font-size: 20px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-left {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
.bottom-left-decoration-1, .bottom-left-decoration-2 {
|
||||
position: absolute;
|
||||
height: 42%;
|
||||
left: 50%;
|
||||
margin-left: -3px;
|
||||
}
|
||||
|
||||
.bottom-left-decoration-1 {
|
||||
top: 8%;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.bottom-left-decoration-2 {
|
||||
bottom: 8%;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-left-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
|
||||
.bli-title {
|
||||
height: 80px;
|
||||
font-size: 20px;
|
||||
line-height: 80px;
|
||||
}
|
||||
|
||||
.bli-value {
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
font-size: 48px;
|
||||
color: rgb(0, 192, 255);
|
||||
font-weight: bold;
|
||||
|
||||
&::after {
|
||||
color: #fff;
|
||||
font-size: 30px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
&.left-value {
|
||||
&::after {
|
||||
content: '%'
|
||||
}
|
||||
}
|
||||
|
||||
&.right-value {
|
||||
&::after {
|
||||
content: '小时'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bli-chart {
|
||||
height: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.bottom-right-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
margin: 0 -5px;
|
||||
padding: 20px 25px;
|
||||
|
||||
.title-item {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 20px;
|
||||
|
||||
img {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
vertical-align: middle;
|
||||
margin-left: 20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-board {
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|