Commit e4fc4173e243afacd7383984c9041661030ff0bf
1 parent
71637956
feat(component): add echarts component !#zh: 支持echarts 图表组件📈
Showing
7 changed files
with
1046 additions
and
0 deletions
front-end/h5/package.json
| ... | ... | @@ -21,6 +21,7 @@ |
| 21 | 21 | "animate.css": "^3.7.2", |
| 22 | 22 | "ant-design-vue": "^1.3.14", |
| 23 | 23 | "core-js": "^2.6.5", |
| 24 | + "echarts": "^4.8.0", | |
| 24 | 25 | "element-ui": "^2.13.0", |
| 25 | 26 | "font-awesome": "4.7.0", |
| 26 | 27 | "hotkeys-js": "^3.7.6", |
| ... | ... | @@ -28,7 +29,9 @@ |
| 28 | 29 | "proxy-agent": "^3.1.0", |
| 29 | 30 | "qrcode": "^1.4.1", |
| 30 | 31 | "register-service-worker": "^1.6.2", |
| 32 | + "resize-detector": "^0.2.2", | |
| 31 | 33 | "strapi-sdk-javascript": "^0.3.1", |
| 34 | + "v-charts": "^1.19.0", | |
| 32 | 35 | "v-click-outside": "^2.1.4", |
| 33 | 36 | "vant": "^2.2.12", |
| 34 | 37 | "vue": "^2.6.10", | ... | ... |
front-end/h5/src/components/plugins/charts/chart-mixin.js
0 → 100644
| 1 | +import echarts from 'echarts/lib/echarts' | |
| 2 | +import debounce from 'lodash/debounce' | |
| 3 | +import { addListener, removeListener } from 'resize-detector' | |
| 4 | +import { LineChart } from './chart-model' | |
| 5 | + | |
| 6 | +// TODO 工具函数:获取某个时间段内的时间 | |
| 7 | +function addDays (date, dayStep = 1) { | |
| 8 | + const next = new Date(date) | |
| 9 | + next.setDate(next.getDate() + dayStep) | |
| 10 | + return next | |
| 11 | +} | |
| 12 | + | |
| 13 | +function dateRange (start, end, range = []) { | |
| 14 | + start = new Date(start) | |
| 15 | + end = new Date(end) | |
| 16 | + if (start > end) return range | |
| 17 | + range = [start] | |
| 18 | + while (start < end) { | |
| 19 | + start = addDays(start, 1) | |
| 20 | + range.push(start) | |
| 21 | + } | |
| 22 | + // const next = addDays(start, 1) | |
| 23 | + // return dateRange(next, end, [...range, start]) | |
| 24 | + return range | |
| 25 | +} | |
| 26 | + | |
| 27 | +export default { | |
| 28 | + watch: { | |
| 29 | + dataset: { | |
| 30 | + handler (items) { | |
| 31 | + this.renderChart() | |
| 32 | + } | |
| 33 | + } | |
| 34 | + }, | |
| 35 | + methods: { | |
| 36 | + getXAxis () { | |
| 37 | + const [start, end] = this.dashboard.currentFilterState.daterange | |
| 38 | + if (start === end) return Array.from({ length: 24 }, (_, i) => `${i}`.padStart(2, '0')) | |
| 39 | + return dateRange(start, end).map(date => date.toISOString().slice(0, 10)) | |
| 40 | + }, | |
| 41 | + /** | |
| 42 | + * | |
| 43 | + */ | |
| 44 | + getDataSet () { | |
| 45 | + // const [start, end] = daterange | |
| 46 | + // if (start === end) { | |
| 47 | + // // return this.dataset.map(item => ({...item, s: s.replace(/[\d]{4}-[\d]{2}-[\d]{2}\s+([\d]{2}):[\d]{2}:[\d]{2}/, '$1')) | |
| 48 | + // return this.dataset.map(item => ({ | |
| 49 | + // ...item, | |
| 50 | + // x: `${new Date(item.x).getHours()}`.padStart(2, '0') | |
| 51 | + // })) | |
| 52 | + // } | |
| 53 | + return this.dataset | |
| 54 | + }, | |
| 55 | + renderChart () { | |
| 56 | + const option = new LineChart({ | |
| 57 | + dataset: this.getDataSet(), | |
| 58 | + yIndexMap: { count: 0, sum_base_cpm: 1 } | |
| 59 | + // xAxis: this.getXAxis() | |
| 60 | + }).getOption() | |
| 61 | + // this.option = Object.freeze(option) | |
| 62 | + this.$nextTick(() => { | |
| 63 | + const ele = this.$refs.chart | |
| 64 | + if (ele) { | |
| 65 | + // const chart = window.echarts.init(ele) | |
| 66 | + const chart = echarts.init(ele) | |
| 67 | + this.chart = chart | |
| 68 | + chart.clear() | |
| 69 | + chart.setOption(option) | |
| 70 | + } | |
| 71 | + }) | |
| 72 | + }, | |
| 73 | + autoResize () { | |
| 74 | + this.lastArea = this.getArea() | |
| 75 | + this.__resizeHandler = debounce( | |
| 76 | + () => { | |
| 77 | + if (this.lastArea === 0) { | |
| 78 | + // emulate initial render for initially hidden charts | |
| 79 | + this.mergeOptions({}, true) | |
| 80 | + this.resize() | |
| 81 | + this.mergeOptions(this.options || this.manualOptions || {}, true) | |
| 82 | + } else { | |
| 83 | + this.resize() | |
| 84 | + } | |
| 85 | + this.lastArea = this.getArea() | |
| 86 | + }, | |
| 87 | + 100, | |
| 88 | + { leading: true } | |
| 89 | + ) | |
| 90 | + addListener(this.$el, this.__resizeHandler) | |
| 91 | + } | |
| 92 | + }, | |
| 93 | + mounted () { | |
| 94 | + this.__resizeHandler = debounce( | |
| 95 | + () => { | |
| 96 | + this.chart.resize() | |
| 97 | + }, | |
| 98 | + 500, | |
| 99 | + { leading: true } | |
| 100 | + ) | |
| 101 | + addListener(this.$el, this.__resizeHandler) | |
| 102 | + }, | |
| 103 | + destroy () { | |
| 104 | + removeListener(this.$el, this.__resizeHandler) | |
| 105 | + } | |
| 106 | +} | ... | ... |
front-end/h5/src/components/plugins/charts/chart-model.js
0 → 100644
| 1 | +/** | |
| 2 | + * echarts demo: https://www.echartsjs.com/examples/zh/editor.html?c=line-simple | |
| 3 | + * 通过输入固定格式的 echarts dataset,得到 echarts options | |
| 4 | + * | |
| 5 | + * TODO X轴 formatter:1.只针对 X轴,不针对 tooltip 2. tooltip 和 X轴同时生效 | |
| 6 | + * TODO legend(series) 到多Y轴的映射 | |
| 7 | + */ | |
| 8 | +import _ from 'lodash' | |
| 9 | + | |
| 10 | +export class LineChart { | |
| 11 | + constructor ({ xAxis = [], yIndexMap = {}, dataset }) { | |
| 12 | + this.chartType = 'line' | |
| 13 | + this.colors = { | |
| 14 | + series: [ | |
| 15 | + { value: '#57b2ff' }, | |
| 16 | + { value: '#d70b24' }, | |
| 17 | + { value: '#48c765' }, | |
| 18 | + { value: '#fbb64e' }, | |
| 19 | + { value: '#f95e58' } | |
| 20 | + ], | |
| 21 | + labelText: { | |
| 22 | + xAxis: 'rgba(0,0,0,.6)', | |
| 23 | + yAxis: 'rgba(0,0,0,.6)' | |
| 24 | + }, | |
| 25 | + splitLine: 'rgba(236, 237, 239, 0.26)' | |
| 26 | + } | |
| 27 | + this.yIndexMap = yIndexMap | |
| 28 | + this.dataset = dataset | |
| 29 | + this.keys = { xAxis: 'x', yAxis: 'y', legend: 's' } | |
| 30 | + this.legends = this.getLegends() | |
| 31 | + this.xAxis = (xAxis.length && xAxis) || this.getXAxis() | |
| 32 | + this.yAxis = this.getYAxis(this.legends) | |
| 33 | + this.series = this.getSeries(this.legends, this.xAxis) | |
| 34 | + this.tooltip = this.getTooltip() | |
| 35 | + } | |
| 36 | + /** | |
| 37 | + * 填补缺失值,说白了其实就是 merge | |
| 38 | + * seriesTemplate: [{x: '01-01', y: null}, {x: '02-01', y: null}, {x: '03-01', y: null}] | |
| 39 | + * seriesItemsFromDataSet: [{ x: '01-01', y: 11}, {x: '03-01', y: 33 }] | |
| 40 | + * | |
| 41 | + * => [{x: '01-01', y: 11}, {x: '02-01', y: null}, {x: '03-01', y: 33}] | |
| 42 | + * | |
| 43 | + * seriesTemplate (X轴所有点): ['01-01', '01-02', '01-03] | |
| 44 | + * seriesItemsFromDataSet: 可能缺失的数据作为 填充值 | |
| 45 | + * options: { legend: string // 某条折线图名字 } | |
| 46 | + * | |
| 47 | + * seriesTemplate -> 循环填充默认值 -> [Object, Object] | |
| 48 | + * seriesItemsFromDataSet -> 字典{} -> 循环模板(X轴所有点)-> 找到X轴上点在 seriesItemsFromDataSet字典中的值 ->,替换模板中的默认值 -> 返回填充后的模板 | |
| 49 | + */ | |
| 50 | + padMissingValues (seriesTemplate, seriesItemsFromDataSet, options) { | |
| 51 | + const { xAxis, yAxis, legend } = this.keys | |
| 52 | + const seriesItemsFromDataSetDict = seriesItemsFromDataSet.reduce((obj, curr) => (Object.assign(Object.assign({}, obj), { [curr[xAxis]]: curr })), {}) | |
| 53 | + const templateWithValue = seriesTemplate.map(xAxis => { | |
| 54 | + return (seriesItemsFromDataSetDict[xAxis] || { | |
| 55 | + [legend]: options.legend, | |
| 56 | + [xAxis]: xAxis, | |
| 57 | + [yAxis]: null | |
| 58 | + }) | |
| 59 | + }) | |
| 60 | + return templateWithValue | |
| 61 | + } | |
| 62 | + /** | |
| 63 | + * 对于复杂的数据转换,需要写 ts,方便看懂代码之间的数据流转 | |
| 64 | + * @returns: ['折线图1', '折线图2'] | |
| 65 | + */ | |
| 66 | + getLegends () { | |
| 67 | + const legendKey = this.keys.legend | |
| 68 | + const allLegends = _.uniqBy(this.dataset, legendKey).map((item) => item[legendKey]) | |
| 69 | + const legends = Array.from(new Set(allLegends)) | |
| 70 | + return legends | |
| 71 | + } | |
| 72 | + /** | |
| 73 | + * 获取X轴的数据 | |
| 74 | + * demo: ['01-01', '02-01', '03-01', '04-01'] | |
| 75 | + */ | |
| 76 | + getXAxis () { | |
| 77 | + const xAxis = this.dataset.map(item => item[this.keys.xAxis]) | |
| 78 | + return xAxis | |
| 79 | + } | |
| 80 | + getTooltip () { | |
| 81 | + return { | |
| 82 | + trigger: 'axis' | |
| 83 | + } | |
| 84 | + } | |
| 85 | + getDefaultYAxis (option) { | |
| 86 | + const { show, axisLabelFormatter } = option | |
| 87 | + return { | |
| 88 | + show, | |
| 89 | + type: 'value', | |
| 90 | + axisLabel: { | |
| 91 | + // Y轴文字颜色, | |
| 92 | + color: this.colors.labelText.xAxis, | |
| 93 | + // formatter: '{value}', | |
| 94 | + formatter: axisLabelFormatter | |
| 95 | + }, | |
| 96 | + // 不需要对 Y 轴顶部的文字做定制 | |
| 97 | + // nameTextStyle: { | |
| 98 | + // color: [yAxisTitleFontColor], | |
| 99 | + // fontSize: 14, | |
| 100 | + // fontWeight: 600, | |
| 101 | + // }, | |
| 102 | + // y轴坐标轴轴线, 也就是y轴的一条竖线 | |
| 103 | + axisLine: { | |
| 104 | + show: false, | |
| 105 | + lineStyle: { | |
| 106 | + // y轴上数字的颜色 | |
| 107 | + fontSize: 15, | |
| 108 | + color: this.colors.labelText.yAxis | |
| 109 | + // opacity: 1 | |
| 110 | + } | |
| 111 | + }, | |
| 112 | + // 显示轴线与数值之间的 「-」 | |
| 113 | + axisTick: { show: false }, | |
| 114 | + splitLine: { | |
| 115 | + lineStyle: { | |
| 116 | + // 使用深浅的间隔色 | |
| 117 | + // 类似四条三格的横线的颜色 | |
| 118 | + color: [this.colors.splitLine] | |
| 119 | + } | |
| 120 | + } | |
| 121 | + } | |
| 122 | + } | |
| 123 | + /** | |
| 124 | + * Y轴数据 | |
| 125 | + * @param legends | |
| 126 | + */ | |
| 127 | + getYAxis (legends) { | |
| 128 | + // TODO 如果返回值 函数怎么办呢? | |
| 129 | + function getAxisLabelFormatter (legend) { | |
| 130 | + return function (value) { | |
| 131 | + // const format = formatDict[legend] || "0.0a"; | |
| 132 | + // return numeral(value).format(format); | |
| 133 | + // TODO 自己实现 formatter 函数 | |
| 134 | + return value | |
| 135 | + } | |
| 136 | + } | |
| 137 | + const yAxis = legends.map(legend => this.getDefaultYAxis({ | |
| 138 | + show: window.innerWidth > 768, | |
| 139 | + // TODO 外界传进来legendValueFormatter | |
| 140 | + axisLabelFormatter: getAxisLabelFormatter(legend) | |
| 141 | + })) | |
| 142 | + return yAxis | |
| 143 | + } | |
| 144 | + /** | |
| 145 | + * | |
| 146 | + * @param {*} legends | |
| 147 | + * @param {*} xAxis | |
| 148 | + * | |
| 149 | + interface Series { | |
| 150 | + name: string, | |
| 151 | + data: seriesData, | |
| 152 | + | |
| 153 | + } | |
| 154 | + */ | |
| 155 | + getSeries (legends, xAxis) { | |
| 156 | + /** | |
| 157 | + interface groupbyLegend { | |
| 158 | + [legendKey1]: [ | |
| 159 | + [legendKey1]: legendValue, | |
| 160 | + [xAxiskey]: xAxisValue, | |
| 161 | + [yAxiskey]: yAxisValue | |
| 162 | + ] | |
| 163 | + } | |
| 164 | + */ | |
| 165 | + const groupbyLegend = _.groupBy(this.dataset, this.keys.legend) | |
| 166 | + const series = legends.map((legend, index) => { | |
| 167 | + const seriesItemsFromDataSet = groupbyLegend[legend] | |
| 168 | + const data = this.padMissingValues(xAxis, seriesItemsFromDataSet, { legend }).map(item => item[this.keys.yAxis]) | |
| 169 | + return { | |
| 170 | + name: legend, | |
| 171 | + type: this.chartType, | |
| 172 | + // TODO 值和 value 对应起来 | |
| 173 | + data, | |
| 174 | + yAxisIndex: this.yIndexMap[legend] || 0, | |
| 175 | + itemStyle: { | |
| 176 | + normal: { | |
| 177 | + color: this.colors.series[index].value | |
| 178 | + } | |
| 179 | + // emphasis: { | |
| 180 | + // color: '#59a4ed', | |
| 181 | + // }, | |
| 182 | + } | |
| 183 | + // TODO 指定 Y轴 | |
| 184 | + // TODO zlevel: 0, | |
| 185 | + } | |
| 186 | + }) | |
| 187 | + return series | |
| 188 | + } | |
| 189 | + getDefaultOption () { | |
| 190 | + return { | |
| 191 | + tooltip: { | |
| 192 | + show: true, | |
| 193 | + trigger: 'axis' | |
| 194 | + }, | |
| 195 | + axisTick: { show: false }, | |
| 196 | + xAxis: { | |
| 197 | + type: 'category', | |
| 198 | + boundaryGap: true, | |
| 199 | + axisTick: { show: false }, | |
| 200 | + axisLine: { | |
| 201 | + lineStyle: { | |
| 202 | + // x轴颜色, 包含:x轴的颜色、文字颜色 | |
| 203 | + // 图例: https://jietu.qq.com/upload/index.html?image=http://jietu-10024907.file.myqcloud.com/hwfezrujmosnhjesfoweuqdguwrwyekw.jpg | |
| 204 | + color: 'rgba(0,0,0,.6)' | |
| 205 | + } | |
| 206 | + } | |
| 207 | + }, | |
| 208 | + grid: { | |
| 209 | + left: '3%', | |
| 210 | + right: '4%', | |
| 211 | + bottom: '3%', | |
| 212 | + containLabel: true | |
| 213 | + }, | |
| 214 | + color: this.colors.series | |
| 215 | + } | |
| 216 | + } | |
| 217 | + getOption () { | |
| 218 | + const option = { | |
| 219 | + textStyle: { | |
| 220 | + fontFamily: 'Roboto' | |
| 221 | + }, | |
| 222 | + tooltip: this.tooltip, | |
| 223 | + series: this.series, | |
| 224 | + legend: { | |
| 225 | + data: this.legends, | |
| 226 | + show: true | |
| 227 | + }, | |
| 228 | + xAxis: { | |
| 229 | + data: this.xAxis | |
| 230 | + }, | |
| 231 | + yAxis: this.yAxis | |
| 232 | + } | |
| 233 | + return _.merge(option, this.getDefaultOption()) | |
| 234 | + } | |
| 235 | +} | ... | ... |
front-end/h5/src/components/plugins/charts/chart-model.ts
0 → 100644
| 1 | +/** | |
| 2 | + * echarts demo: https://www.echartsjs.com/examples/zh/editor.html?c=line-simple | |
| 3 | + * 通过输入固定格式的 echarts dataset,得到 echarts options | |
| 4 | + * | |
| 5 | + * TODO X轴 formatter:1.只针对 X轴,不针对 tooltip 2. tooltip 和 X轴同时生效 | |
| 6 | + * TODO legend(series) 到多Y轴的映射 | |
| 7 | + */ | |
| 8 | +import _ from "lodash"; | |
| 9 | +// import numeral from "numeral"; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * | |
| 13 | + yIndexMap: { | |
| 14 | + 系列1: 0, | |
| 15 | + 系列2: 1 | |
| 16 | + } | |
| 17 | + | |
| 18 | + const users = [ | |
| 19 | + { | |
| 20 | + x: "2010/01/01 00:00:00", | |
| 21 | + y: 500, | |
| 22 | + s: "系列1" | |
| 23 | + }, | |
| 24 | + { | |
| 25 | + x: "2010/01/01 00:00:00", | |
| 26 | + y: 180, | |
| 27 | + s: "系列2" | |
| 28 | + }, | |
| 29 | + { | |
| 30 | + x: "2010/02/01 00:00:00", | |
| 31 | + y: 250, | |
| 32 | + s: "系列1" | |
| 33 | + }, | |
| 34 | + { | |
| 35 | + x: "2010/02/01 00:00:00", | |
| 36 | + y: 100, | |
| 37 | + s: "系列2" | |
| 38 | + }, | |
| 39 | + { | |
| 40 | + x: "2010/03/01 00:00:00", | |
| 41 | + y: 325, | |
| 42 | + s: "系列1" | |
| 43 | + }, | |
| 44 | + { | |
| 45 | + x: "2010/03/01 00:00:00", | |
| 46 | + y: 175, | |
| 47 | + s: "系列2" | |
| 48 | + }, | |
| 49 | + { | |
| 50 | + x: "2010/04/01 00:00:00", | |
| 51 | + y: 190, | |
| 52 | + s: "系列1" | |
| 53 | + }, | |
| 54 | + { | |
| 55 | + x: "2010/04/01 00:00:00", | |
| 56 | + y: 110, | |
| 57 | + s: "系列2" | |
| 58 | + }, | |
| 59 | + { | |
| 60 | + x: "2010/05/01 00:00:00", | |
| 61 | + y: 260, | |
| 62 | + s: "系列1" | |
| 63 | + }, | |
| 64 | + { | |
| 65 | + x: "2010/05/01 00:00:00", | |
| 66 | + y: 60, | |
| 67 | + s: "系列2" | |
| 68 | + }, | |
| 69 | + { | |
| 70 | + x: "2010/05/19 00:00:00", | |
| 71 | + y: 90, | |
| 72 | + s: "系列2" | |
| 73 | + }, | |
| 74 | + { | |
| 75 | + x: "2010/05/23 00:00:00", | |
| 76 | + y: 90, | |
| 77 | + s: "系列2" | |
| 78 | + } | |
| 79 | + ]; | |
| 80 | + | |
| 81 | + * | |
| 82 | + */ | |
| 83 | + | |
| 84 | +// 固定格式 | |
| 85 | +interface DataSetItem { | |
| 86 | + x: string; // x轴 | |
| 87 | + y: string | number; // y轴,也就是 value | |
| 88 | + s: string | number; // s 也就是 legend | |
| 89 | + [propName: string]: any; | |
| 90 | +} | |
| 91 | + | |
| 92 | +interface SeriesItemDict { | |
| 93 | + [propName: string]: any; | |
| 94 | +} | |
| 95 | + | |
| 96 | +interface SeriesItem { | |
| 97 | + name?: string; // 可选 | |
| 98 | + type: string; | |
| 99 | + data: Array<string | number>; | |
| 100 | + itemStyle: { | |
| 101 | + normal: { | |
| 102 | + color: string; | |
| 103 | + }; | |
| 104 | + // emphasis: { | |
| 105 | + // color: '#59a4ed', | |
| 106 | + // }, | |
| 107 | + }; | |
| 108 | + yAxisIndex?: number | |
| 109 | + // TODO 指定 Y轴 | |
| 110 | + // TODO zlevel: 0, | |
| 111 | +} | |
| 112 | + | |
| 113 | +interface YAxisOption { | |
| 114 | + show: boolean; | |
| 115 | + axisLabelFormatter: (value: any) => any; | |
| 116 | +} | |
| 117 | + | |
| 118 | +interface formatDictType { | |
| 119 | + [propName: string]: string; | |
| 120 | +} | |
| 121 | + | |
| 122 | +interface uniqByResultType { | |
| 123 | + [legendKey: string]: string // legendValue | |
| 124 | +} | |
| 125 | + | |
| 126 | +interface LineChartConfig { | |
| 127 | + xAxis?: Array<string|number>; | |
| 128 | + dataset: DataSetItem[]; | |
| 129 | + yIndexMap: { | |
| 130 | + [legendkey: string]: number | |
| 131 | + } | |
| 132 | +} | |
| 133 | + | |
| 134 | +const formatDict: formatDictType = { | |
| 135 | + gp: "$0.00", | |
| 136 | + gross_profit: "$0.00", | |
| 137 | + revenue: "$0.00", | |
| 138 | + reveue_f: "$0.00", | |
| 139 | + cvr: "0.00%", | |
| 140 | + click_count: "0,00", | |
| 141 | + conv: "0,00", | |
| 142 | + show_rate: "0.00%", | |
| 143 | + fill_rate: "0.00%" | |
| 144 | +}; | |
| 145 | + | |
| 146 | +export class LineChart { | |
| 147 | + // 指定折线采用哪一条Y轴 | |
| 148 | + yIndexMap: { | |
| 149 | + // 纬度/折线 | |
| 150 | + [legendName: string]: number | |
| 151 | + }; | |
| 152 | + chartType: string; // 'line' | 'bar' | 'pie' | |
| 153 | + // TODO class 里面如何定义 ts | |
| 154 | + colors: { | |
| 155 | + series: any; | |
| 156 | + labelText: any; | |
| 157 | + splitLine: string; | |
| 158 | + }; | |
| 159 | + // 数据源 | |
| 160 | + dataset: DataSetItem[]; | |
| 161 | + keys: { | |
| 162 | + xAxis: string; | |
| 163 | + yAxis: string; | |
| 164 | + legend: string; | |
| 165 | + }; | |
| 166 | + legends: string[]; | |
| 167 | + xAxis: Array<string | number>; | |
| 168 | + yAxis: any[]; | |
| 169 | + series: Array<SeriesItem>; | |
| 170 | + tooltip: any; | |
| 171 | + | |
| 172 | + constructor({ | |
| 173 | + xAxis = [], | |
| 174 | + yIndexMap = {}, | |
| 175 | + dataset | |
| 176 | + } : LineChartConfig | |
| 177 | + ) { | |
| 178 | + this.chartType = "line"; | |
| 179 | + this.colors = { | |
| 180 | + series: [ | |
| 181 | + { value: "#57b2ff" }, | |
| 182 | + { value: "#d70b24" }, | |
| 183 | + { value: "#48c765" }, | |
| 184 | + { value: "#fbb64e" }, | |
| 185 | + { value: "#f95e58" } | |
| 186 | + ], | |
| 187 | + labelText: { | |
| 188 | + xAxis: "rgba(0,0,0,.6)", | |
| 189 | + yAxis: "rgba(0,0,0,.6)" | |
| 190 | + }, | |
| 191 | + splitLine: "rgba(236, 237, 239, 0.26)" | |
| 192 | + }; | |
| 193 | + this.yIndexMap = yIndexMap; | |
| 194 | + this.dataset = dataset; | |
| 195 | + this.keys = { xAxis: "x", yAxis: "y", legend: "s" }; | |
| 196 | + | |
| 197 | + this.legends = this.getLegends(); | |
| 198 | + this.xAxis = (xAxis.length && xAxis) || this.getXAxis(); | |
| 199 | + this.yAxis = this.getYAxis(this.legends); | |
| 200 | + this.series = this.getSeries(this.legends, this.xAxis); | |
| 201 | + this.tooltip = this.getTooltip(); | |
| 202 | + } | |
| 203 | + | |
| 204 | + /** | |
| 205 | + * 填补缺失值,说白了其实就是 merge | |
| 206 | + * seriesTemplate: [{x: '01-01', y: null}, {x: '02-01', y: null}, {x: '03-01', y: null}] | |
| 207 | + * seriesItemsFromDataSet: [{ x: '01-01', y: 11}, {x: '03-01', y: 33 }] | |
| 208 | + * | |
| 209 | + * => [{x: '01-01', y: 11}, {x: '02-01', y: null}, {x: '03-01', y: 33}] | |
| 210 | + * | |
| 211 | + * seriesTemplate (X轴所有点): ['01-01', '01-02', '01-03] | |
| 212 | + * seriesItemsFromDataSet: 可能缺失的数据作为 填充值 | |
| 213 | + * options: { legend: string // 某条折线图名字 } | |
| 214 | + * | |
| 215 | + * seriesTemplate -> 循环填充默认值 -> [Object, Object] | |
| 216 | + * seriesItemsFromDataSet -> 字典{} -> 循环模板(X轴所有点)-> 找到X轴上点在 seriesItemsFromDataSet字典中的值 ->,替换模板中的默认值 -> 返回填充后的模板 | |
| 217 | + */ | |
| 218 | + padMissingValues( | |
| 219 | + seriesTemplate: Array<string | number>, | |
| 220 | + seriesItemsFromDataSet: DataSetItem[], | |
| 221 | + options: { legend: string } | |
| 222 | + ): DataSetItem[] { | |
| 223 | + const { xAxis, yAxis, legend } = this.keys; | |
| 224 | + | |
| 225 | + const seriesItemsFromDataSetDict: SeriesItemDict = seriesItemsFromDataSet.reduce( | |
| 226 | + (obj, curr: DataSetItem) => ({ | |
| 227 | + ...obj, | |
| 228 | + [curr[xAxis]]: curr | |
| 229 | + }), | |
| 230 | + {} | |
| 231 | + ); | |
| 232 | + | |
| 233 | + const templateWithValue = seriesTemplate.map(xAxis => { | |
| 234 | + return ( | |
| 235 | + seriesItemsFromDataSetDict[xAxis] || { | |
| 236 | + [legend]: options.legend, | |
| 237 | + [xAxis]: xAxis, | |
| 238 | + [yAxis]: null | |
| 239 | + } | |
| 240 | + ); | |
| 241 | + }); | |
| 242 | + | |
| 243 | + return templateWithValue; | |
| 244 | + } | |
| 245 | + | |
| 246 | + /** | |
| 247 | + * 对于复杂的数据转换,需要写 ts,方便看懂代码之间的数据流转 | |
| 248 | + * @returns: ['折线图1', '折线图2'] | |
| 249 | + */ | |
| 250 | + getLegends(): string[] { | |
| 251 | + const legendKey = this.keys.legend; | |
| 252 | + const allLegends: string[] = _.uniqBy(this.dataset, legendKey).map( | |
| 253 | + (item: uniqByResultType) => item[legendKey] | |
| 254 | + ); | |
| 255 | + const legends: string[] = Array.from(new Set(allLegends)); | |
| 256 | + return legends; | |
| 257 | + } | |
| 258 | + | |
| 259 | + /** | |
| 260 | + * 获取X轴的数据 | |
| 261 | + * demo: ['01-01', '02-01', '03-01', '04-01'] | |
| 262 | + */ | |
| 263 | + getXAxis(): Array<string | number> { | |
| 264 | + const xAxis = this.dataset.map(item => item[this.keys.xAxis]); | |
| 265 | + return xAxis; | |
| 266 | + } | |
| 267 | + | |
| 268 | + getTooltip(): any { | |
| 269 | + return { | |
| 270 | + trigger: "axis" | |
| 271 | + }; | |
| 272 | + } | |
| 273 | + | |
| 274 | + getDefaultYAxis(option: YAxisOption) { | |
| 275 | + const { show, axisLabelFormatter } = option; | |
| 276 | + return { | |
| 277 | + show, | |
| 278 | + type: "value", | |
| 279 | + axisLabel: { | |
| 280 | + // Y轴文字颜色, | |
| 281 | + color: this.colors.labelText.xAxis, | |
| 282 | + // formatter: '{value}', | |
| 283 | + formatter: axisLabelFormatter | |
| 284 | + }, | |
| 285 | + // 不需要对 Y 轴顶部的文字做定制 | |
| 286 | + // nameTextStyle: { | |
| 287 | + // color: [yAxisTitleFontColor], | |
| 288 | + // fontSize: 14, | |
| 289 | + // fontWeight: 600, | |
| 290 | + // }, | |
| 291 | + // y轴坐标轴轴线, 也就是y轴的一条竖线 | |
| 292 | + axisLine: { | |
| 293 | + show: false, | |
| 294 | + lineStyle: { | |
| 295 | + // y轴上数字的颜色 | |
| 296 | + fontSize: 15, | |
| 297 | + color: this.colors.labelText.yAxis | |
| 298 | + // opacity: 1 | |
| 299 | + } | |
| 300 | + }, | |
| 301 | + // 显示轴线与数值之间的 「-」 | |
| 302 | + axisTick: { show: false }, | |
| 303 | + splitLine: { | |
| 304 | + lineStyle: { | |
| 305 | + // 使用深浅的间隔色 | |
| 306 | + // 类似四条三格的横线的颜色 | |
| 307 | + color: [this.colors.splitLine] | |
| 308 | + } | |
| 309 | + } | |
| 310 | + }; | |
| 311 | + } | |
| 312 | + | |
| 313 | + /** | |
| 314 | + * Y轴数据 | |
| 315 | + * @param legends | |
| 316 | + */ | |
| 317 | + getYAxis(legends: string[]): any[] { | |
| 318 | + // TODO 如果返回值 函数怎么办呢? | |
| 319 | + function getAxisLabelFormatter(legend: string) { | |
| 320 | + return function(value: any) { | |
| 321 | + // const format = formatDict[legend] || "0.0a"; | |
| 322 | + // return numeral(value).format(format); | |
| 323 | + // TODO 自己实现 formatter 函数 | |
| 324 | + return value | |
| 325 | + }; | |
| 326 | + } | |
| 327 | + const yAxis = legends.map(legend => | |
| 328 | + this.getDefaultYAxis({ | |
| 329 | + show: window.innerWidth > 768, | |
| 330 | + // TODO 外界传进来legendValueFormatter | |
| 331 | + axisLabelFormatter: getAxisLabelFormatter(legend) | |
| 332 | + }) | |
| 333 | + ); | |
| 334 | + return yAxis; | |
| 335 | + } | |
| 336 | + | |
| 337 | + /** | |
| 338 | + * | |
| 339 | + * @param {*} legends | |
| 340 | + * @param {*} xAxis | |
| 341 | + * | |
| 342 | + interface Series { | |
| 343 | + name: string, | |
| 344 | + data: seriesData, | |
| 345 | + | |
| 346 | + } | |
| 347 | + */ | |
| 348 | + getSeries(legends: string[], xAxis: Array<string | number>): SeriesItem[] { | |
| 349 | + /** | |
| 350 | + interface groupbyLegend { | |
| 351 | + [legendKey1]: [ | |
| 352 | + [legendKey1]: legendValue, | |
| 353 | + [xAxiskey]: xAxisValue, | |
| 354 | + [yAxiskey]: yAxisValue | |
| 355 | + ] | |
| 356 | + } | |
| 357 | + */ | |
| 358 | + const groupbyLegend = _.groupBy(this.dataset, this.keys.legend); | |
| 359 | + const series = legends.map((legend: string, index: number) => { | |
| 360 | + const seriesItemsFromDataSet: DataSetItem[] = groupbyLegend[legend]; | |
| 361 | + const data: Array<string | number> = this.padMissingValues( | |
| 362 | + xAxis, | |
| 363 | + seriesItemsFromDataSet, | |
| 364 | + { legend } | |
| 365 | + ).map(item => item[this.keys.yAxis]); | |
| 366 | + return { | |
| 367 | + name: legend, // 可选 | |
| 368 | + type: this.chartType, | |
| 369 | + // TODO 值和 value 对应起来 | |
| 370 | + data, | |
| 371 | + yAxisIndex: this.yIndexMap[legend] || 0, | |
| 372 | + itemStyle: { | |
| 373 | + normal: { | |
| 374 | + color: this.colors.series[index].value | |
| 375 | + } | |
| 376 | + // emphasis: { | |
| 377 | + // color: '#59a4ed', | |
| 378 | + // }, | |
| 379 | + } | |
| 380 | + // TODO 指定 Y轴 | |
| 381 | + // TODO zlevel: 0, | |
| 382 | + }; | |
| 383 | + }); | |
| 384 | + return series; | |
| 385 | + } | |
| 386 | + | |
| 387 | + getDefaultOption() { | |
| 388 | + return { | |
| 389 | + tooltip: { | |
| 390 | + show: true, | |
| 391 | + trigger: "axis" | |
| 392 | + }, | |
| 393 | + axisTick: { show: false }, | |
| 394 | + xAxis: { | |
| 395 | + type: "category", | |
| 396 | + boundaryGap: true, | |
| 397 | + axisTick: { show: false }, | |
| 398 | + axisLine: { | |
| 399 | + lineStyle: { | |
| 400 | + // x轴颜色, 包含:x轴的颜色、文字颜色 | |
| 401 | + // 图例: https://jietu.qq.com/upload/index.html?image=http://jietu-10024907.file.myqcloud.com/hwfezrujmosnhjesfoweuqdguwrwyekw.jpg | |
| 402 | + color: "rgba(0,0,0,.6)" | |
| 403 | + } | |
| 404 | + } | |
| 405 | + }, | |
| 406 | + grid: { | |
| 407 | + y: 40, // 图表和legend之间的距离 | |
| 408 | + left: "5%", // 图表的x轴的零点距离容器左侧的距离 | |
| 409 | + right: "4%", // 图表的x轴的最右点距离容器右侧的距离 | |
| 410 | + bottom: 30 | |
| 411 | + }, | |
| 412 | + color: this.colors.series | |
| 413 | + }; | |
| 414 | + } | |
| 415 | + | |
| 416 | + getOption() { | |
| 417 | + const option = { | |
| 418 | + textStyle: { | |
| 419 | + fontFamily: "Roboto" | |
| 420 | + }, | |
| 421 | + tooltip: this.tooltip, | |
| 422 | + series: this.series, | |
| 423 | + legend: { | |
| 424 | + data: this.legends, | |
| 425 | + show: true | |
| 426 | + }, | |
| 427 | + xAxis: { | |
| 428 | + data: this.xAxis | |
| 429 | + }, | |
| 430 | + yAxis: this.yAxis | |
| 431 | + }; | |
| 432 | + return _.merge(option, this.getDefaultOption()); | |
| 433 | + } | |
| 434 | +} | |
| 0 | 435 | \ No newline at end of file | ... | ... |
front-end/h5/src/components/plugins/charts/line.js
0 → 100644
| 1 | +import VeLine from 'v-charts/lib/line.common' | |
| 2 | +import VePie from 'v-charts/lib/pie.common' | |
| 3 | +import VeHistogram from 'v-charts/lib/histogram.common' | |
| 4 | +import VeFunnel from 'v-charts/lib/funnel.common' | |
| 5 | +import PropTypes from '@luban-h5/plugin-common-props' | |
| 6 | +import 'echarts/lib/component/legend' | |
| 7 | +import 'echarts/lib/component/markLine' | |
| 8 | +import 'echarts/lib/component/markPoint' | |
| 9 | +import 'echarts/lib/component/markArea' | |
| 10 | +import Parser from '../../../utils/excel-parser' | |
| 11 | + | |
| 12 | +export default { | |
| 13 | + extra: { | |
| 14 | + defaultStyle: { | |
| 15 | + width: 320, | |
| 16 | + height: 400 | |
| 17 | + } | |
| 18 | + }, | |
| 19 | + name: 'lbp-line-chart', | |
| 20 | + // mixins: [ChartMixin], | |
| 21 | + props: { | |
| 22 | + dataset: PropTypes.excel({ | |
| 23 | + defaultValue: () => [ | |
| 24 | + ['日期', '销售量'], | |
| 25 | + ['1月1日', 123], | |
| 26 | + ['1月2日', 1223], | |
| 27 | + ['1月3日', 2123], | |
| 28 | + ['1月4日', 4123], | |
| 29 | + ['1月5日', 3123], | |
| 30 | + ['1月6日', 7123] | |
| 31 | + ] | |
| 32 | + }), | |
| 33 | + type: PropTypes.string({ | |
| 34 | + label: '类型', | |
| 35 | + defaultValue: 'line', | |
| 36 | + visible: false | |
| 37 | + }) | |
| 38 | + }, | |
| 39 | + data () { | |
| 40 | + return { | |
| 41 | + option: {} | |
| 42 | + } | |
| 43 | + }, | |
| 44 | + render () { | |
| 45 | + const chartData = Parser.csv2VChartJson(this.dataset) | |
| 46 | + const settings = { | |
| 47 | + // metrics: ['日期', '销售量'], | |
| 48 | + // dimension: ['日期'] | |
| 49 | + } | |
| 50 | + switch (this.type) { | |
| 51 | + case 'line': | |
| 52 | + return <VeLine data={chartData} settings={settings} /> | |
| 53 | + case 'histogram': | |
| 54 | + return <VeHistogram data={chartData} settings={settings} /> | |
| 55 | + case 'pie': | |
| 56 | + return <VePie data={chartData} settings={settings} /> | |
| 57 | + case 'funnel': | |
| 58 | + return <VeFunnel data={chartData} settings={settings} /> | |
| 59 | + default: | |
| 60 | + return null | |
| 61 | + } | |
| 62 | + }, | |
| 63 | + mounted () { | |
| 64 | + // this.renderChart() | |
| 65 | + } | |
| 66 | +} | ... | ... |
front-end/h5/src/utils/excel-parser.js
0 → 100644
| 1 | +/** | |
| 2 | + * | |
| 3 | + declare module ExcelRows { | |
| 4 | + export interface cell { | |
| 5 | + text: string; | |
| 6 | + } | |
| 7 | + export interface Cells { | |
| 8 | + 0: cell; | |
| 9 | + 1: cell; | |
| 10 | + 2: cell; | |
| 11 | + } | |
| 12 | + export interface ExcelRows { | |
| 13 | + cells: Cells; | |
| 14 | + } | |
| 15 | +} | |
| 16 | + */ | |
| 17 | + | |
| 18 | +/** | |
| 19 | + * | |
| 20 | + BinaryMatrix = [ | |
| 21 | + [any, any, any, ...], | |
| 22 | + [any, any, any, ...], | |
| 23 | + [any, any, any, ...], | |
| 24 | + ] | |
| 25 | + | |
| 26 | + ExcelDataType = [ | |
| 27 | + { | |
| 28 | + cells: { | |
| 29 | + 0: { text: any }, | |
| 30 | + 1: { text: any }, | |
| 31 | + 2: { text: any } | |
| 32 | + } | |
| 33 | + }, | |
| 34 | + { | |
| 35 | + cells: { | |
| 36 | + 0: { text: any }, | |
| 37 | + 1: { text: any }, | |
| 38 | + 2: { text: any } | |
| 39 | + } | |
| 40 | + }, | |
| 41 | + ] | |
| 42 | + */ | |
| 43 | + | |
| 44 | +export default class Parser { | |
| 45 | + /** | |
| 46 | + * | |
| 47 | + * @param {*} dataset ExcelDataType | |
| 48 | + */ | |
| 49 | + static dataset2excel (dataset) { | |
| 50 | + return dataset.map(item => ({ | |
| 51 | + cells: { | |
| 52 | + 0: { text: item.x }, | |
| 53 | + 1: { text: item.y }, | |
| 54 | + 2: { text: item.s } | |
| 55 | + } | |
| 56 | + })) | |
| 57 | + } | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * | |
| 61 | + [ | |
| 62 | + [1,2,3,4], | |
| 63 | + [5,6,7,8], | |
| 64 | + [9,10,11,12] | |
| 65 | + ] | |
| 66 | + * @param {Object} BinaryMatrix | |
| 67 | + * @returns {Object} ExcelDataType | |
| 68 | + */ | |
| 69 | + static binaryMatrix2excel (binaryMatrix) { | |
| 70 | + const excelData = binaryMatrix.map((row, rowIndex) => { | |
| 71 | + // cells: { | |
| 72 | + // 0: { text: item.x }, | |
| 73 | + // 1: { text: item.y }, | |
| 74 | + // 2: { text: item.s } | |
| 75 | + // } | |
| 76 | + const cells = {} | |
| 77 | + row.forEach((cellValue, cellIndex) => { | |
| 78 | + cells[cellIndex] = { text: cellValue } | |
| 79 | + }) | |
| 80 | + return { cells } | |
| 81 | + }) | |
| 82 | + return excelData | |
| 83 | + } | |
| 84 | + | |
| 85 | + static excel2chartDataSet (excelData) { | |
| 86 | + const rowsArray = Object.values(excelData.rows).filter(item => typeof item === 'object') | |
| 87 | + const dataset = rowsArray.map(row => { | |
| 88 | + const [x, y, s] = Object.values(row.cells).map(item => item.text) | |
| 89 | + return { | |
| 90 | + x: x, | |
| 91 | + y: y, | |
| 92 | + s: s | |
| 93 | + } | |
| 94 | + }) | |
| 95 | + return dataset | |
| 96 | + } | |
| 97 | + | |
| 98 | + static excel2BinaryMatrix (excelData) { | |
| 99 | + const rowsArray = Object.values(excelData.rows).filter(item => typeof item === 'object') | |
| 100 | + const dataset = rowsArray.map(row => { | |
| 101 | + // [1,2,3,4] | |
| 102 | + const cells = Object.values(row.cells).map(item => item.text) | |
| 103 | + return cells | |
| 104 | + }) | |
| 105 | + console.log('dataset', dataset) | |
| 106 | + return dataset | |
| 107 | + } | |
| 108 | + | |
| 109 | + /** | |
| 110 | + * | |
| 111 | + * @param {Array} csvArray | |
| 112 | + * [ | |
| 113 | + ['日期', '销售量'], | |
| 114 | + ["1月1日",123], | |
| 115 | + ["1月2日",1223], | |
| 116 | + ["1月3日",2123], | |
| 117 | + ["1月4日",4123], | |
| 118 | + ["1月5日",3123], | |
| 119 | + ["1月6日",7123] | |
| 120 | + ] | |
| 121 | + * @returns {Object} | |
| 122 | + { | |
| 123 | + columns: ['日期', '销售量'], | |
| 124 | + rows:[ | |
| 125 | + { '日期': '1月1日', '销售量': 123 }, | |
| 126 | + { '日期': '1月2日', '销售量': 1223 }, | |
| 127 | + { '日期': '1月3日', '销售量': 2123 }, | |
| 128 | + { '日期': '1月4日', '销售量': 4123 }, | |
| 129 | + { '日期': '1月5日', '销售量': 3123 }, | |
| 130 | + { '日期': '1月6日', '销售量': 7123 } | |
| 131 | + ] | |
| 132 | + } | |
| 133 | + */ | |
| 134 | + static csv2VChartJson (csvArray) { | |
| 135 | + const columns = csvArray[0] | |
| 136 | + const rows = csvArray.slice(1) | |
| 137 | + const json = { | |
| 138 | + columns, | |
| 139 | + rows: rows.map((row, index) => { | |
| 140 | + const obj = {} | |
| 141 | + columns.forEach((col, colIndex) => { | |
| 142 | + obj[col] = row[colIndex] | |
| 143 | + }) | |
| 144 | + return obj | |
| 145 | + }) | |
| 146 | + } | |
| 147 | + return json | |
| 148 | + } | |
| 149 | +} | ... | ... |
front-end/h5/yarn.lock
| ... | ... | @@ -3684,6 +3684,28 @@ ecc-jsbn@~0.1.1: |
| 3684 | 3684 | jsbn "~0.1.0" |
| 3685 | 3685 | safer-buffer "^2.1.0" |
| 3686 | 3686 | |
| 3687 | +echarts-amap@1.0.0-rc.6: | |
| 3688 | + version "1.0.0-rc.6" | |
| 3689 | + resolved "https://registry.npm.taobao.org/echarts-amap/download/echarts-amap-1.0.0-rc.6.tgz#5782a74daee52ed44ce3f8f62577561783f09e16" | |
| 3690 | + integrity sha1-V4KnTa7lLtRM4/j2JXdWF4PwnhY= | |
| 3691 | + | |
| 3692 | +echarts-liquidfill@^2.0.2: | |
| 3693 | + version "2.0.6" | |
| 3694 | + resolved "https://registry.npm.taobao.org/echarts-liquidfill/download/echarts-liquidfill-2.0.6.tgz#0668dc61d87a6262003090bd32c55aa8108c252e" | |
| 3695 | + integrity sha1-BmjcYdh6YmIAMJC9MsVaqBCMJS4= | |
| 3696 | + | |
| 3697 | +echarts-wordcloud@^1.1.3: | |
| 3698 | + version "1.1.3" | |
| 3699 | + resolved "https://registry.npm.taobao.org/echarts-wordcloud/download/echarts-wordcloud-1.1.3.tgz#07b140c8ba76b19c317b43c310f3d5dc99289ff2" | |
| 3700 | + integrity sha1-B7FAyLp2sZwxe0PDEPPV3Jkon/I= | |
| 3701 | + | |
| 3702 | +echarts@^4.8.0: | |
| 3703 | + version "4.8.0" | |
| 3704 | + resolved "https://registry.npm.taobao.org/echarts/download/echarts-4.8.0.tgz?cache=0&sync_timestamp=1596214937248&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fecharts%2Fdownload%2Fecharts-4.8.0.tgz#b2c1cfb9229b13d368ee104fc8eea600b574d4c4" | |
| 3705 | + integrity sha1-ssHPuSKbE9No7hBPyO6mALV01MQ= | |
| 3706 | + dependencies: | |
| 3707 | + zrender "4.3.1" | |
| 3708 | + | |
| 3687 | 3709 | editorconfig@^0.15.3: |
| 3688 | 3710 | version "0.15.3" |
| 3689 | 3711 | resolved "https://registry.npm.taobao.org/editorconfig/download/editorconfig-0.15.3.tgz#bef84c4e75fb8dcb0ce5cee8efd51c15999befc5" |
| ... | ... | @@ -7556,6 +7578,11 @@ number-is-nan@^1.0.0: |
| 7556 | 7578 | resolved "https://registry.npm.taobao.org/number-is-nan/download/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" |
| 7557 | 7579 | integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= |
| 7558 | 7580 | |
| 7581 | +numerify@1.2.9: | |
| 7582 | + version "1.2.9" | |
| 7583 | + resolved "https://registry.npm.taobao.org/numerify/download/numerify-1.2.9.tgz#af4696bb1d57f8d3970a615d8b0cd53d932bd559" | |
| 7584 | + integrity sha1-r0aWux1X+NOXCmFdiwzVPZMr1Vk= | |
| 7585 | + | |
| 7559 | 7586 | nwsapi@^2.0.7: |
| 7560 | 7587 | version "2.2.0" |
| 7561 | 7588 | resolved "https://registry.npm.taobao.org/nwsapi/download/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" |
| ... | ... | @@ -9208,6 +9235,11 @@ reselect@^3.0.1: |
| 9208 | 9235 | resolved "https://registry.npm.taobao.org/reselect/download/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" |
| 9209 | 9236 | integrity sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc= |
| 9210 | 9237 | |
| 9238 | +resize-detector@^0.2.2: | |
| 9239 | + version "0.2.2" | |
| 9240 | + resolved "https://registry.npm.taobao.org/resize-detector/download/resize-detector-0.2.2.tgz#b207e72912bef0bda9fb825fe894ed9686ca965e" | |
| 9241 | + integrity sha1-sgfnKRK+8L2p+4Jf6JTtlobKll4= | |
| 9242 | + | |
| 9211 | 9243 | resize-observer-polyfill@^1.5.0, resize-observer-polyfill@^1.5.1: |
| 9212 | 9244 | version "1.5.1" |
| 9213 | 9245 | resolved "https://registry.npm.taobao.org/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" |
| ... | ... | @@ -10681,6 +10713,11 @@ utila@^0.4.0, utila@~0.4: |
| 10681 | 10713 | resolved "https://registry.npm.taobao.org/utila/download/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" |
| 10682 | 10714 | integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= |
| 10683 | 10715 | |
| 10716 | +utils-lite@0.1.10: | |
| 10717 | + version "0.1.10" | |
| 10718 | + resolved "https://registry.npm.taobao.org/utils-lite/download/utils-lite-0.1.10.tgz#d2908c0482e23c31e6b082558540e7134ffad7d7" | |
| 10719 | + integrity sha1-0pCMBILiPDHmsIJVhUDnE0/619c= | |
| 10720 | + | |
| 10684 | 10721 | utils-merge@1.0.1: |
| 10685 | 10722 | version "1.0.1" |
| 10686 | 10723 | resolved "https://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" |
| ... | ... | @@ -10691,6 +10728,17 @@ uuid@^3.0.1, uuid@^3.3.2: |
| 10691 | 10728 | resolved "https://registry.npm.taobao.org/uuid/download/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" |
| 10692 | 10729 | integrity sha1-RWjwIW54dg7h2/Ok0s9T4iQRKGY= |
| 10693 | 10730 | |
| 10731 | +v-charts@^1.19.0: | |
| 10732 | + version "1.19.0" | |
| 10733 | + resolved "https://registry.npm.taobao.org/v-charts/download/v-charts-1.19.0.tgz#07b701800b159bd514264ffc8bf12b0405142da3" | |
| 10734 | + integrity sha1-B7cBgAsVm9UUJk/8i/ErBAUULaM= | |
| 10735 | + dependencies: | |
| 10736 | + echarts-amap "1.0.0-rc.6" | |
| 10737 | + echarts-liquidfill "^2.0.2" | |
| 10738 | + echarts-wordcloud "^1.1.3" | |
| 10739 | + numerify "1.2.9" | |
| 10740 | + utils-lite "0.1.10" | |
| 10741 | + | |
| 10694 | 10742 | v-click-outside@^2.1.4: |
| 10695 | 10743 | version "2.1.4" |
| 10696 | 10744 | resolved "https://registry.npm.taobao.org/v-click-outside/download/v-click-outside-2.1.4.tgz#7d7813b09a0fd4a9d0fbccc2ca12ca7c5591e087" |
| ... | ... | @@ -11459,3 +11507,8 @@ yorkie@^2.0.0: |
| 11459 | 11507 | is-ci "^1.0.10" |
| 11460 | 11508 | normalize-path "^1.0.0" |
| 11461 | 11509 | strip-indent "^2.0.0" |
| 11510 | + | |
| 11511 | +zrender@4.3.1: | |
| 11512 | + version "4.3.1" | |
| 11513 | + resolved "https://registry.npm.taobao.org/zrender/download/zrender-4.3.1.tgz?cache=0&sync_timestamp=1596718864550&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fzrender%2Fdownload%2Fzrender-4.3.1.tgz#baf8aa6dc8187a2f819692d7d5f9bedfa2b90fa3" | |
| 11514 | + integrity sha1-uviqbcgYei+BlpLX1fm+36K5D6M= | ... | ... |