UNPKG

vue-chart-component

Version:

基于echarts的图表组件库,

1,690 lines (1,592 loc) 4.11 MB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["vue-chart-component"] = factory(); else root["vue-chart-component"] = factory(); })((typeof self !== 'undefined' ? self : this), function() { return /******/ (function() { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ 1410: /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { "default": function() { return /* binding */ vue_chart_base; } }); ;// CONCATENATED MODULE: ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-82.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/templateLoader.js??ruleSet[1].rules[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./src/package/vue-chart-base/index.vue?vue&type=template&id=6e1e1270&scoped=true& var render = function render() { var _vm = this, _c = _vm._self._c; return _c('div', { staticClass: "vChart-container" }, [_vm.hasData ? _c('div', { staticClass: "vChart", attrs: { "id": _vm.chartId } }) : _c('div', [_vm._v(" 暂无数据 ")])]); }; var staticRenderFns = []; // EXTERNAL MODULE: ./node_modules/core-js/modules/es.array.push.js var es_array_push = __webpack_require__(7658); // EXTERNAL MODULE: ./node_modules/echarts/index.js + 365 modules var echarts = __webpack_require__(5289); // EXTERNAL MODULE: ./src/package/utils.js var utils = __webpack_require__(4941); ;// CONCATENATED MODULE: ./src/package/vue-chart-base/config.js // 传参示例 const paramsExample = { data: [{ type: 'line', // 可选 图表类型 默认柱图bar name: '折线图', // 必传 名称 value: [10, 20, 30, 40], // 必传 数值 showYAxis: true, // 可选 是否显示y轴 position: 'right', // y轴位置 默认left yAxisName: '单位:%', // 可选 y轴名称 stack: true, // 可选 是否为堆叠柱图 默认false type值为bar且至少有两组柱图时有效 series: {} // 可选 自定义series配置 }, { name: '柱图', value: [10, 20, 30, 40] }], // 每个对象为一组数据 可同时绘制柱图、折线图、堆叠柱图 xAxisData: ['2023-01', '2023-02', '2023-03', '2023-04'], // 必传 x轴数据 title: '', // 可选 标题 option: { title: { text: '' } } // 可选 echarts 参数配置 }; let startColorList = ['25, 214, 156', '29, 184, 255', '255, 191, 70', '108, 96, 253']; let endColorList = ['170, 255, 107', '47, 253, 248', '253, 222, 165', '191, 186, 255']; // 图表颜色 const getColor = data => { let startColor = startColorList; let endColor = endColorList; if (data.length > startColor.length || data.length > endColor.length) { startColor = startColor.concat(startColor.slice(0, data.length - startColor.length)); endColor = endColor.concat(endColor.slice(0, data.length - endColor.length)); } return { startColor, endColor }; }; // 默认图表类型 const defaultType = 'bar'; // 折线图基础数据 const lineBaseSeries = (startColor = startColorList[0], endColor = endColorList[0]) => { return { type: 'line', smooth: true, showSymbol: false, lineStyle: { width: 2, color: `rgba(${startColor}, 1)` // 线条颜色 }, itemStyle: { color: `rgba(${startColor}, 1)`, borderColor: '#646ace', borderWidth: 2 }, areaStyle: { color: { type: 'linear', x: 0, y: 0, x2: 0, y2: 1, colorStops: [{ offset: 0, color: `rgba(${startColor}, 1)` // 0% 处的颜色 }, { offset: 0.2, color: `rgba(${endColor}, 0.5)` }, { offset: 1, color: `rgba(0,0,0,0)` }], globalCoord: false // 缺省为 false } } }; }; // 柱图基础数据 const barBaseSeries = (startColor = startColorList[0], endColor = endColorList[0], stack = false) => { return { type: 'bar', stack: stack, barMaxWidth: '30', itemStyle: { borderColor: `rgba(${startColor}, 0.2)`, borderWidth: '1', color: { type: 'linear', x: 0, y: 0, x2: 0, y2: 1, colorStops: [{ offset: 0, color: `rgba(${startColor}, 1)` // 0% 处的颜色 }, { offset: 0.2, color: `rgba(${endColor}, 0.5)` }, { offset: 1, color: `rgba(0,0,0,0)` }], globalCoord: false // 缺省为 false } } }; }; const baseSeriesConfig = { line: lineBaseSeries, bar: barBaseSeries }; ;// CONCATENATED MODULE: ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-82.use[1]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./src/package/vue-chart-base/index.vue?vue&type=script&lang=js& let idx = 1; /* harmony default export */ var vue_chart_basevue_type_script_lang_js_ = ({ name: 'vue-chart-base', data() { return { myChart: null, chartId: '', deepAssign: utils/* deepAssign */.n }; }, props: { data: { type: Array, default: () => [] }, xAxisData: { type: Array, default: () => [] }, title: { type: String, default: '' }, option: { type: Object, default: () => ({}) } }, computed: { hasData() { return this.data.length; }, baseYAxis() { return { type: 'value', nameTextStyle: { color: 'rgba(181, 217, 255, 0.5)' }, axisLabel: { color: '#B5D9FF' }, axisLine: { show: true, lineStyle: { color: 'rgba(221, 238, 253, 0.2)', width: 2 } }, axisTick: { show: false }, splitLine: { show: true, lineStyle: { type: 'dashed', color: 'rgba(221, 238, 253, 0.1)' } } }; } }, watch: { data() { this.$nextTick(() => { this.setChatOption(); }); } }, created() { this.chartId = `vChart_base_${idx++}`; }, mounted() { this.setChatOption(); }, methods: { initChart() { const dom = document.getElementById(this.chartId); if (!dom) { return; } this.myChart = echarts/* init */.S1(dom); }, handleData() { const { baseYAxis, data, xAxisData } = this; const { startColor, endColor } = getColor(data); const series = []; let yAxisList = []; data.map((item, index) => { if (item.showYAxis) { const min = Math.min.apply(null, item.value); const max = Math.max.apply(null, item.value); yAxisList.push({ ...baseYAxis, ...{ name: item.yAxisName, position: item.position || 'left', min: Math.floor((min - min * 0.1) / 10) * 10, max: Math.ceil((max + max * 0.1) / 10) * 10 } }); } let baseType = baseSeriesConfig[defaultType]; if (item.type && baseSeriesConfig[item.type]) { baseType = baseSeriesConfig[item.type]; } const baseSeries = baseType(startColor[item.colorIndex || index], endColor[item.colorIndex || index], item.stack); series.push({ name: item.name, yAxisIndex: item.showYAxis ? yAxisList.length - 1 : 0, ...baseSeries, data: [...item.value], ...item.series }); }); yAxisList = yAxisList.length === 0 ? [baseYAxis] : yAxisList; return { xAxisData, yAxisList, series }; }, setChatOption() { if (!this.hasData) { this.myChart && this.myChart.dispose(); this.myChart = null; return; } const { option, title } = this; const { xAxisData, yAxisList, series } = this.handleData(); let opt = { title: { show: title, text: title, left: 'center', textStyle: { color: '#ffffff', fontSize: 14, lineHeight: 20 } }, grid: { left: '15%', top: '15%', right: '15%', bottom: '20%' }, legend: { bottom: '5%', textStyle: { color: '#B5D9FF' } }, tooltip: { trigger: 'axis', backgroundColor: 'rgba(50, 50, 50, 0.7)', borderColor: 'rgb(51, 51, 51)', borderRadius: 5, textStyle: { fontSize: 12, color: '#fff' }, axisPointer: { lineStyle: { color: { type: 'linear', x: 0, y: 0, x2: 0, y2: 1, colorStops: [{ offset: 0, color: 'rgba(255,255,255,0)' // 0% 处的颜色 }, { offset: 0.5, color: 'rgba(255,255,255,1)' // 100% 处的颜色 }, { offset: 1, color: 'rgba(195,255,250,1)' // 100% 处的颜色 }], global: false // 缺省为 false } } } }, dataZoom: [{ type: 'inside', start: 0, end: 100 }], xAxis: { type: 'category', axisLabel: { //坐标轴刻度标签的相关配置 color: '#B5D9FF' }, axisLine: { //坐标轴轴线相关配置 show: true, lineStyle: { color: 'rgba(221, 238, 253, 0.2)', width: 2 } }, axisTick: { show: false }, splitLine: { show: false }, data: xAxisData }, yAxis: yAxisList, series: series }; const opts = this.deepAssign(opt, option); !this.myChart && this.initChart(); this.myChart && this.myChart.setOption(opts); window.addEventListener('resize', () => { this.myChart.resize(); }); } } }); ;// CONCATENATED MODULE: ./src/package/vue-chart-base/index.vue?vue&type=script&lang=js& /* harmony default export */ var package_vue_chart_basevue_type_script_lang_js_ = (vue_chart_basevue_type_script_lang_js_); ;// CONCATENATED MODULE: ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-64.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-64.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-64.use[2]!./node_modules/sass-loader/dist/cjs.js??clonedRuleSet-64.use[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./src/package/vue-chart-base/index.vue?vue&type=style&index=0&id=6e1e1270&prod&lang=scss&scoped=true& // extracted by mini-css-extract-plugin ;// CONCATENATED MODULE: ./src/package/vue-chart-base/index.vue?vue&type=style&index=0&id=6e1e1270&prod&lang=scss&scoped=true& // EXTERNAL MODULE: ./node_modules/@vue/vue-loader-v15/lib/runtime/componentNormalizer.js var componentNormalizer = __webpack_require__(1001); ;// CONCATENATED MODULE: ./src/package/vue-chart-base/index.vue ; /* normalize component */ var component = (0,componentNormalizer/* default */.Z)( package_vue_chart_basevue_type_script_lang_js_, render, staticRenderFns, false, null, "6e1e1270", null ) /* harmony default export */ var vue_chart_base = (component.exports); /***/ }), /***/ 4117: /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { "default": function() { return /* binding */ vue_chart_liquidfill; } }); ;// CONCATENATED MODULE: ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-82.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/templateLoader.js??ruleSet[1].rules[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./src/package/vue-chart-liquidfill/index.vue?vue&type=template&id=acd9ee14&scoped=true& var render = function render() { var _vm = this, _c = _vm._self._c; return _c('div', { staticClass: "vChart-container" }, [_vm.hasData ? _c('div', { staticClass: "vChart-box" }, [_c('div', { staticClass: "vChart", attrs: { "id": _vm.chartId } }), _c('div', { staticClass: "liquid-title", style: { 'color': `rgb(${_vm.opt_color})` } }, [_c('span', { staticClass: "liquid-num" }, [_vm._v(_vm._s(_vm.formatNum(_vm.data.num)))]), _c('span', [_vm._v(_vm._s(_vm.data.name))])])]) : _c('div', [_vm._v(" 暂无数据 ")])]); }; var staticRenderFns = []; // EXTERNAL MODULE: ./node_modules/echarts/index.js + 365 modules var echarts = __webpack_require__(5289); // EXTERNAL MODULE: ./node_modules/echarts/lib/export/core.js + 3 modules var core = __webpack_require__(4067); // EXTERNAL MODULE: ./node_modules/echarts/lib/extension.js var extension = __webpack_require__(5480); // EXTERNAL MODULE: ./node_modules/echarts/lib/core/echarts.js + 16 modules var core_echarts = __webpack_require__(5355); // EXTERNAL MODULE: ./node_modules/echarts/lib/renderer/installCanvasRenderer.js + 2 modules var installCanvasRenderer = __webpack_require__(4446); // EXTERNAL MODULE: ./node_modules/echarts/lib/component/dataset/install.js var install = __webpack_require__(9520); // EXTERNAL MODULE: ./node_modules/echarts/lib/label/installLabelLayout.js + 1 modules var installLabelLayout = __webpack_require__(7890); ;// CONCATENATED MODULE: ./node_modules/echarts/lib/echarts.js /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** * AUTO-GENERATED FILE. DO NOT MODIFY. */ /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // Default to have canvas renderer and dataset for compitatble reason. (0,extension/* use */.D)([installCanvasRenderer/* install */.N, install/* install */.N]); // TODO: Compatitable with the following code // import echarts from 'echarts/lib/echarts.js' /* harmony default export */ var lib_echarts = ({ init: function () { if (false) {} // @ts-ignore return core_echarts/* init */.S1.apply(null, arguments); } }); // Import label layout by default. // TODO remove (0,extension/* use */.D)(installLabelLayout/* installLabelLayout */.T); ;// CONCATENATED MODULE: ./node_modules/echarts-liquidfill/src/liquidFillSeries.js core/* extendSeriesModel */.Zr({ type: 'series.liquidFill', optionUpdated: function () { var option = this.option; option.gridSize = Math.max(Math.floor(option.gridSize), 4); }, getInitialData: function (option, ecModel) { var dimensions = core/* helper.createDimensions */._y.createDimensions(option.data, { coordDimensions: ['value'] }); var list = new core/* List */.aV(dimensions, this); list.initData(option.data); return list; }, defaultOption: { color: ['#294D99', '#156ACF', '#1598ED', '#45BDFF'], center: ['50%', '50%'], radius: '50%', amplitude: '8%', waveLength: '80%', phase: 'auto', period: 'auto', direction: 'right', shape: 'circle', waveAnimation: true, animationEasing: 'linear', animationEasingUpdate: 'linear', animationDuration: 2000, animationDurationUpdate: 1000, outline: { show: true, borderDistance: 8, itemStyle: { color: 'none', borderColor: '#294D99', borderWidth: 8, shadowBlur: 20, shadowColor: 'rgba(0, 0, 0, 0.25)' } }, backgroundStyle: { color: '#E3F7FF' }, itemStyle: { opacity: 0.95, shadowBlur: 50, shadowColor: 'rgba(0, 0, 0, 0.4)' }, label: { show: true, color: '#294D99', insideColor: '#fff', fontSize: 50, fontWeight: 'bold', align: 'center', baseline: 'middle', position: 'inside' }, emphasis: { itemStyle: { opacity: 0.8 } } } }); // EXTERNAL MODULE: ./node_modules/core-js/modules/es.array.push.js var es_array_push = __webpack_require__(7658); // EXTERNAL MODULE: ./node_modules/echarts/lib/util/number.js var number = __webpack_require__(8662); ;// CONCATENATED MODULE: ./node_modules/echarts-liquidfill/src/liquidFillShape.js /* harmony default export */ var liquidFillShape = (core/* graphic.extendShape */.Q.extendShape({ type: 'ec-liquid-fill', shape: { waveLength: 0, radius: 0, radiusY: 0, cx: 0, cy: 0, waterLevel: 0, amplitude: 0, phase: 0, inverse: false }, buildPath: function (ctx, shape) { if (shape.radiusY == null) { shape.radiusY = shape.radius; } /** * We define a sine wave having 4 waves, and make sure at least 8 curves * is drawn. Otherwise, it may cause blank area for some waves when * wave length is large enough. */ var curves = Math.max(Math.ceil(2 * shape.radius / shape.waveLength * 4) * 2, 8); // map phase to [-Math.PI * 2, 0] while (shape.phase < -Math.PI * 2) { shape.phase += Math.PI * 2; } while (shape.phase > 0) { shape.phase -= Math.PI * 2; } var phase = shape.phase / Math.PI / 2 * shape.waveLength; var left = shape.cx - shape.radius + phase - shape.radius * 2; /** * top-left corner as start point * * draws this point * | * \|/ * ~~~~~~~~ * | | * +------+ */ ctx.moveTo(left, shape.waterLevel); /** * top wave * * ~~~~~~~~ <- draws this sine wave * | | * +------+ */ var waveRight = 0; for (var c = 0; c < curves; ++c) { var stage = c % 4; var pos = getWaterPositions(c * shape.waveLength / 4, stage, shape.waveLength, shape.amplitude); ctx.bezierCurveTo(pos[0][0] + left, -pos[0][1] + shape.waterLevel, pos[1][0] + left, -pos[1][1] + shape.waterLevel, pos[2][0] + left, -pos[2][1] + shape.waterLevel); if (c === curves - 1) { waveRight = pos[2][0]; } } if (shape.inverse) { /** * top-right corner * 2. draws this line * | * +------+ * 3. draws this line -> | | <- 1. draws this line * ~~~~~~~~ */ ctx.lineTo(waveRight + left, shape.cy - shape.radiusY); ctx.lineTo(left, shape.cy - shape.radiusY); ctx.lineTo(left, shape.waterLevel); } else { /** * top-right corner * * ~~~~~~~~ * 3. draws this line -> | | <- 1. draws this line * +------+ * ^ * | * 2. draws this line */ ctx.lineTo(waveRight + left, shape.cy + shape.radiusY); ctx.lineTo(left, shape.cy + shape.radiusY); ctx.lineTo(left, shape.waterLevel); } ctx.closePath(); } })); /** * Using Bezier curves to fit sine wave. * There is 4 control points for each curve of wave, * which is at 1/4 wave length of the sine wave. * * The control points for a wave from (a) to (d) are a-b-c-d: * c *----* d * b * * | * ... a * .................. * * whose positions are a: (0, 0), b: (0.5, 0.5), c: (1, 1), d: (PI / 2, 1) * * @param {number} x x position of the left-most point (a) * @param {number} stage 0-3, stating which part of the wave it is * @param {number} waveLength wave length of the sine wave * @param {number} amplitude wave amplitude */ function getWaterPositions(x, stage, waveLength, amplitude) { if (stage === 0) { return [[x + 1 / 2 * waveLength / Math.PI / 2, amplitude / 2], [x + 1 / 2 * waveLength / Math.PI, amplitude], [x + waveLength / 4, amplitude]]; } else if (stage === 1) { return [[x + 1 / 2 * waveLength / Math.PI / 2 * (Math.PI - 2), amplitude], [x + 1 / 2 * waveLength / Math.PI / 2 * (Math.PI - 1), amplitude / 2], [x + waveLength / 4, 0]]; } else if (stage === 2) { return [[x + 1 / 2 * waveLength / Math.PI / 2, -amplitude / 2], [x + 1 / 2 * waveLength / Math.PI, -amplitude], [x + waveLength / 4, -amplitude]]; } else { return [[x + 1 / 2 * waveLength / Math.PI / 2 * (Math.PI - 2), -amplitude], [x + 1 / 2 * waveLength / Math.PI / 2 * (Math.PI - 1), -amplitude / 2], [x + waveLength / 4, 0]]; } } ;// CONCATENATED MODULE: ./node_modules/echarts-liquidfill/src/liquidFillView.js var parsePercent = number/* parsePercent */.GM; function isPathSymbol(symbol) { return symbol && symbol.indexOf('path://') === 0; } core/* extendChartView */.Zy({ type: 'liquidFill', render: function (seriesModel, ecModel, api) { var self = this; var group = this.group; group.removeAll(); var data = seriesModel.getData(); var itemModel = data.getItemModel(0); var center = itemModel.get('center'); var radius = itemModel.get('radius'); var width = api.getWidth(); var height = api.getHeight(); var size = Math.min(width, height); // itemStyle var outlineDistance = 0; var outlineBorderWidth = 0; var showOutline = seriesModel.get('outline.show'); if (showOutline) { outlineDistance = seriesModel.get('outline.borderDistance'); outlineBorderWidth = parsePercent(seriesModel.get('outline.itemStyle.borderWidth'), size); } var cx = parsePercent(center[0], width); var cy = parsePercent(center[1], height); var outterRadius; var innerRadius; var paddingRadius; var isFillContainer = false; var symbol = seriesModel.get('shape'); if (symbol === 'container') { // a shape that fully fills the container isFillContainer = true; outterRadius = [width / 2, height / 2]; innerRadius = [outterRadius[0] - outlineBorderWidth / 2, outterRadius[1] - outlineBorderWidth / 2]; paddingRadius = [parsePercent(outlineDistance, width), parsePercent(outlineDistance, height)]; radius = [Math.max(innerRadius[0] - paddingRadius[0], 0), Math.max(innerRadius[1] - paddingRadius[1], 0)]; } else { outterRadius = parsePercent(radius, size) / 2; innerRadius = outterRadius - outlineBorderWidth / 2; paddingRadius = parsePercent(outlineDistance, size); radius = Math.max(innerRadius - paddingRadius, 0); } if (showOutline) { var outline = getOutline(); outline.style.lineWidth = outlineBorderWidth; group.add(getOutline()); } var left = isFillContainer ? 0 : cx - radius; var top = isFillContainer ? 0 : cy - radius; var wavePath = null; group.add(getBackground()); // each data item for a wave var oldData = this._data; var waves = []; data.diff(oldData).add(function (idx) { var wave = getWave(idx, false); var waterLevel = wave.shape.waterLevel; wave.shape.waterLevel = isFillContainer ? height / 2 : radius; core/* graphic.initProps */.Q.initProps(wave, { shape: { waterLevel: waterLevel } }, seriesModel); wave.z2 = 2; setWaveAnimation(idx, wave, null); group.add(wave); data.setItemGraphicEl(idx, wave); waves.push(wave); }).update(function (newIdx, oldIdx) { var waveElement = oldData.getItemGraphicEl(oldIdx); // new wave is used to calculate position, but not added var newWave = getWave(newIdx, false, waveElement); // changes with animation var shape = {}; var shapeAttrs = ['amplitude', 'cx', 'cy', 'phase', 'radius', 'radiusY', 'waterLevel', 'waveLength']; for (var i = 0; i < shapeAttrs.length; ++i) { var attr = shapeAttrs[i]; if (newWave.shape.hasOwnProperty(attr)) { shape[attr] = newWave.shape[attr]; } } var style = {}; var styleAttrs = ['fill', 'opacity', 'shadowBlur', 'shadowColor']; for (var i = 0; i < styleAttrs.length; ++i) { var attr = styleAttrs[i]; if (newWave.style.hasOwnProperty(attr)) { style[attr] = newWave.style[attr]; } } if (isFillContainer) { shape.radiusY = height / 2; } // changes with animation core/* graphic.updateProps */.Q.updateProps(waveElement, { shape: shape, x: newWave.x, y: newWave.y }, seriesModel); if (seriesModel.isUniversalTransitionEnabled && seriesModel.isUniversalTransitionEnabled()) { core/* graphic.updateProps */.Q.updateProps(waveElement, { style: style }, seriesModel); } else { waveElement.useStyle(style); } // instant changes var oldWaveClipPath = waveElement.getClipPath(); var newWaveClipPath = newWave.getClipPath(); waveElement.setClipPath(newWave.getClipPath()); waveElement.shape.inverse = newWave.inverse; if (oldWaveClipPath && newWaveClipPath && self._shape === symbol // TODO use zrender morphing to apply complex symbol animation. && !isPathSymbol(symbol)) { // Can be animated. core/* graphic.updateProps */.Q.updateProps(newWaveClipPath, { shape: oldWaveClipPath.shape }, seriesModel, { isFrom: true }); } setWaveAnimation(newIdx, waveElement, waveElement); group.add(waveElement); data.setItemGraphicEl(newIdx, waveElement); waves.push(waveElement); }).remove(function (idx) { var wave = oldData.getItemGraphicEl(idx); group.remove(wave); }).execute(); if (itemModel.get('label.show')) { group.add(getText(waves)); } this._shape = symbol; this._data = data; /** * Get path for outline, background and clipping * * @param {number} r outter radius of shape * @param {boolean|undefined} isForClipping if the shape is used * for clipping */ function getPath(r, isForClipping) { if (symbol) { // customed symbol path if (isPathSymbol(symbol)) { var path = core/* graphic.makePath */.Q.makePath(symbol.slice(7), {}); var bouding = path.getBoundingRect(); var w = bouding.width; var h = bouding.height; if (w > h) { h = r * 2 / w * h; w = r * 2; } else { w = r * 2 / h * w; h = r * 2; } var left = isForClipping ? 0 : cx - w / 2; var top = isForClipping ? 0 : cy - h / 2; path = core/* graphic.makePath */.Q.makePath(symbol.slice(7), {}, new core/* graphic.BoundingRect */.Q.BoundingRect(left, top, w, h)); if (isForClipping) { path.x = -w / 2; path.y = -h / 2; } return path; } else if (isFillContainer) { // fully fill the container var x = isForClipping ? -r[0] : cx - r[0]; var y = isForClipping ? -r[1] : cy - r[1]; return core/* helper.createSymbol */._y.createSymbol('rect', x, y, r[0] * 2, r[1] * 2); } else { var x = isForClipping ? -r : cx - r; var y = isForClipping ? -r : cy - r; if (symbol === 'pin') { y += r; } else if (symbol === 'arrow') { y -= r; } return core/* helper.createSymbol */._y.createSymbol(symbol, x, y, r * 2, r * 2); } } return new core/* graphic.Circle */.Q.Circle({ shape: { cx: isForClipping ? 0 : cx, cy: isForClipping ? 0 : cy, r: r } }); } /** * Create outline */ function getOutline() { var outlinePath = getPath(outterRadius); outlinePath.style.fill = null; outlinePath.setStyle(seriesModel.getModel('outline.itemStyle').getItemStyle()); return outlinePath; } /** * Create background */ function getBackground() { // Seperate stroke and fill, so we can use stroke to cover the alias of clipping. var strokePath = getPath(radius); strokePath.setStyle(seriesModel.getModel('backgroundStyle').getItemStyle()); strokePath.style.fill = null; // Stroke is front of wave strokePath.z2 = 5; var fillPath = getPath(radius); fillPath.setStyle(seriesModel.getModel('backgroundStyle').getItemStyle()); fillPath.style.stroke = null; var group = new core/* graphic.Group */.Q.Group(); group.add(strokePath); group.add(fillPath); return group; } /** * wave shape */ function getWave(idx, isInverse, oldWave) { var radiusX = isFillContainer ? radius[0] : radius; var radiusY = isFillContainer ? height / 2 : radius; var itemModel = data.getItemModel(idx); var itemStyleModel = itemModel.getModel('itemStyle'); var phase = itemModel.get('phase'); var amplitude = parsePercent(itemModel.get('amplitude'), radiusY * 2); var waveLength = parsePercent(itemModel.get('waveLength'), radiusX * 2); var value = data.get('value', idx); var waterLevel = radiusY - value * radiusY * 2; phase = oldWave ? oldWave.shape.phase : phase === 'auto' ? idx * Math.PI / 4 : phase; var normalStyle = itemStyleModel.getItemStyle(); if (!normalStyle.fill) { var seriesColor = seriesModel.get('color'); var id = idx % seriesColor.length; normalStyle.fill = seriesColor[id]; } var x = radiusX * 2; var wave = new liquidFillShape({ shape: { waveLength: waveLength, radius: radiusX, radiusY: radiusY, cx: x, cy: 0, waterLevel: waterLevel, amplitude: amplitude, phase: phase, inverse: isInverse }, style: normalStyle, x: cx, y: cy }); wave.shape._waterLevel = waterLevel; var hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle(); hoverStyle.lineWidth = 0; wave.ensureState('emphasis').style = hoverStyle; core/* helper.enableHoverEmphasis */._y.enableHoverEmphasis(wave); // clip out the part outside the circle var clip = getPath(radius, true); // set fill for clipPath, otherwise it will not trigger hover event clip.setStyle({ fill: 'white' }); wave.setClipPath(clip); return wave; } function setWaveAnimation(idx, wave, oldWave) { var itemModel = data.getItemModel(idx); var maxSpeed = itemModel.get('period'); var direction = itemModel.get('direction'); var value = data.get('value', idx); var phase = itemModel.get('phase'); phase = oldWave ? oldWave.shape.phase : phase === 'auto' ? idx * Math.PI / 4 : phase; var defaultSpeed = function (maxSpeed) { var cnt = data.count(); return cnt === 0 ? maxSpeed : maxSpeed * (0.2 + (cnt - idx) / cnt * 0.8); }; var speed = 0; if (maxSpeed === 'auto') { speed = defaultSpeed(5000); } else { speed = typeof maxSpeed === 'function' ? maxSpeed(value, idx) : maxSpeed; } // phase for moving left/right var phaseOffset = 0; if (direction === 'right' || direction == null) { phaseOffset = Math.PI; } else if (direction === 'left') { phaseOffset = -Math.PI; } else if (direction === 'none') { phaseOffset = 0; } else { console.error('Illegal direction value for liquid fill.'); } // wave animation of moving left/right if (direction !== 'none' && itemModel.get('waveAnimation')) { wave.animate('shape', true).when(0, { phase: phase }).when(speed / 2, { phase: phaseOffset + phase }).when(speed, { phase: phaseOffset * 2 + phase }).during(function () { if (wavePath) { wavePath.dirty(true); } }).start(); } } /** * text on wave */ function getText(waves) { var labelModel = itemModel.getModel('label'); function formatLabel() { var formatted = seriesModel.getFormattedLabel(0, 'normal'); var defaultVal = data.get('value', 0) * 100; var defaultLabel = data.getName(0) || seriesModel.name; if (!isNaN(defaultVal)) { defaultLabel = defaultVal.toFixed(0) + '%'; } return formatted == null ? defaultLabel : formatted; } var textRectOption = { z2: 10, shape: { x: left, y: top, width: (isFillContainer ? radius[0] : radius) * 2, height: (isFillContainer ? radius[1] : radius) * 2 }, style: { fill: 'transparent' }, textConfig: { position: labelModel.get('position') || 'inside' }, silent: true }; var textOption = { style: { text: formatLabel(), textAlign: labelModel.get('align'), textVerticalAlign: labelModel.get('baseline') } }; Object.assign(textOption.style, core/* helper.createTextStyle */._y.createTextStyle(labelModel)); var outsideTextRect = new core/* graphic.Rect */.Q.Rect(textRectOption); var insideTextRect = new core/* graphic.Rect */.Q.Rect(textRectOption); insideTextRect.disableLabelAnimation = true; outsideTextRect.disableLabelAnimation = true; var outsideText = new core/* graphic.Text */.Q.Text(textOption); var insideText = new core/* graphic.Text */.Q.Text(textOption); outsideTextRect.setTextContent(outsideText); insideTextRect.setTextContent(insideText); var insColor = labelModel.get('insideColor'); insideText.style.fill = insColor; var group = new core/* graphic.Group */.Q.Group(); group.add(outsideTextRect); group.add(insideTextRect); // clip out waves for insideText var boundingCircle = getPath(radius, true); wavePath = new core/* graphic.CompoundPath */.Q.CompoundPath({ shape: { paths: waves }, x: cx, y: cy }); wavePath.setClipPath(boundingCircle); insideTextRect.setClipPath(wavePath); return group; } }, dispose: function () { // dispose nothing here } }); ;// CONCATENATED MODULE: ./node_modules/echarts-liquidfill/src/liquidFill.js ;// CONCATENATED MODULE: ./node_modules/echarts-liquidfill/index.js ;// CONCATENATED MODULE: ./src/package/vue-chart-liquidfill/config.js // 传参示例 const paramsExample = { data: { value: 0.8, // 必传 百分比数值 范围0-1 colorIndex: 1, // 可选 使用的颜色序号 不传默认使用第一个颜色 color: '64, 158, 255', // 可选 自定义颜色 参数值为rgb颜色 有此参数时默认颜色序号无效 name: '默认样式2', // 可选 标题 num: 12121, // 可选 数值 thousandFormatNum: true // 可选 数值是否千分位格式化 默认为false }, option: { title: { text: '' } }, // 可选 echarts 参数配置 series: {} // 可选 echarts 数值配置 }; // 默认颜色 const defaultColorList = ['64, 158, 255', '103, 194, 58', '230, 162, 60']; // 默认标题配置 const defaultTitleOpt = { text: '', textStyle: { fontWeight: 'normal', fontSize: 25, color: 'rgb(97, 142, 205)' } }; // 默认参数配置 const defaultOpts = { backgroundColor: 'transparent', // 背景颜色 title: defaultTitleOpt }; // EXTERNAL MODULE: ./src/package/utils.js var utils = __webpack_require__(4941); ;// CONCATENATED MODULE: ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-82.use[1]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./src/package/vue-chart-liquidfill/index.vue?vue&type=script&lang=js& let idx = 1; /* harmony default export */ var vue_chart_liquidfillvue_type_script_lang_js_ = ({ name: 'vue-chart-liquidfill', props: { data: { type: Object, default: {} }, option: { type: Object, default: () => ({}) }, series: { type: Object, default: () => ({}) } }, data() { return { myChart: null, chartId: '', deepAssign: utils/* deepAssign */.n }; }, computed: { hasData() { return this.data && Object.keys(this.data).length; }, formatNum() { return val => { const thousandFormatNum = this.data.thousandFormatNum; return thousandFormatNum ? (0,utils/* thousandFormat */.P)(val) : val; }; }, // 颜色 opt_color() { let { color, colorIndex } = this.data; colorIndex && colorIndex--; const defaultColor = defaultColorList[colorIndex] ? defaultColorList[colorIndex] : defaultColorList[0]; return color || defaultColor; }, // 参数配置 opts() { return this.deepAssign(defaultOpts, this.option); }, defaultSeries() { const { value } = this.data; const { opt_color } = this; const numList = [value, value, value]; const series = { type: 'liquidFill', radius: '90%', data: numList, // 波纹颜色 color: [{ type: 'linear', x: 0, y: 0, x2: 0, y2: 1, colorStops: [{ offset: 1, color: 'rgba(58, 71, 212, 0)' }, { offset: 0.5, color: 'rgba(31, 222, 225, .2)' }, { offset: 0, color: `rgba(${opt_color}, 1)` }], globalCoord: false }], // 内部背景色 backgroundStyle: { color: { type: 'linear', x: 1, y: 0, x2: 0.5, y2: 1, colorStops: [{ offset: 1, color: 'rgba(68, 145, 253, 0)' }, { offset: 0.5, color: 'rgba(68, 145, 253, .25)' }, { offset: 0, color: 'rgba(68, 145, 253, 1)' }], globalCoord: false } }, // 外边框颜色 上至下 outline: { borderDistance: 8, // 边框与内部距离 itemStyle: { borderWidth: 3, borderColor: { type: 'linear', x: 0, y: 0, x2: 0, y2: 1, colorStops: [{ offset: 0, color: 'rgba(69, 73, 240, 1)' }, { offset: 0.7, color: 'rgba(69, 73, 240, .25)' }, { offset: 1, color: `rgba(${opt_color}, 1)` }], globalCoord: false }, shadowBlur: 10, shadowColor: '#000' } }, // 中间百分比数值 label: { fontSize: 20, color: '#06c8f9' } }; return series; }, opt_series() { return this.deepAssign(this.defaultSeries, this.series); } }, watch: { data() { this.$nextTick(() => { this.setChatOption(); }); } }, created() { this.chartId = `vChart_liquidFill_${idx++}`; }, mounted() { this.setChatOption(); }, methods: { initChart() { const dom = document.getElementById(this.chartId); if (!dom) { return; } this.myChart = echarts/* init */.S1(dom); }, setChatOption() { if (!this.hasData) { this.myChart && this.myChart.dispose(); this.myChart = null; return; } const { opts, opt_series } = this; let option = { series: [opt_series], ...opts }; !this.myChart && this.initChart(); this.myChart && this.myChart.setOption(option); window.addEventListener('resize', () => { this.myChart.resize(); }); } } }); ;// CONCATENATED MODULE: ./src/package/vue-chart-liquidfill/index.vue?vue&type=script&lang=js& /* harmony default export */ var package_vue_chart_liquidfillvue_type_script_lang_js_ = (vue_chart_liquidfillvue_type_script_lang_js_); ;// CONCATENATED MODULE: ./node_modules/mini-css-extract-plugin/dist/loader.js??clonedRuleSet-64.use[0]!./node_modules/css-loader/dist/cjs.js??clonedRuleSet-64.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/dist/cjs.js??clonedRuleSet-64.use[2]!./node_modules/sass-loader/dist/cjs.js??clonedRuleSet-64.use[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./src/package/vue-chart-liquidfill/index.vue?vue&type=style&index=0&id=acd9ee14&prod&lang=scss&scoped=true& // extracted by mini-css-extract-plugin ;// CONCATENATED MODULE: ./src/package/vue-chart-liquidfill/index.vue?vue&type=style&index=0&id=acd9ee14&prod&lang=scss&scoped=true& // EXTERNAL MODULE: ./node_modules/@vue/vue-loader-v15/lib/runtime/componentNormalizer.js var componentNormalizer = __webpack_require__(1001); ;// CONCATENATED MODULE: ./src/package/vue-chart-liquidfill/index.vue ; /* normalize component */ var component = (0,componentNormalizer/* default */.Z)( package_vue_chart_liquidfillvue_type_script_lang_js_, render, staticRenderFns, false, null, "acd9ee14", null ) /* harmony default export */ var vue_chart_liquidfill = (component.exports); /***/ }), /***/ 882: /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; // ESM COMPAT FLAG __webpack_require__.r(__webpack_exports__); // EXPORTS __webpack_require__.d(__webpack_exports__, { "default": function() { return /* binding */ vue_chart_pie; } }); ;// CONCATENATED MODULE: ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-82.use[1]!./node_modules/@vue/vue-loader-v15/lib/loaders/templateLoader.js??ruleSet[1].rules[3]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./src/package/vue-chart-pie/index.vue?vue&type=template&id=57e958ae&scoped=true& var render = function render() { var _vm = this, _c = _vm._self._c; return _c('div', { staticClass: "vChart-container" }, [_vm.hasData ? _c('div', { staticClass: "vChart", attrs: { "id": _vm.chartId } }) : _c('div', [_vm._v(" 暂无数据 ")])]); }; var staticRenderFns = []; // EXTERNAL MODULE: ./node_modules/core-js/modules/es.array.push.js var es_array_push = __webpack_require__(7658); // EXTERNAL MODULE: ./src/package/utils.js var utils = __webpack_require__(4941); ;// CONCATENATED MODULE: ./src/package/vue-chart-pie/config.js // 传参示例 const paramsExample = { data: [{ name: 'xx', // 必传 名称 value: '1', // 必传 数值 ratio: '20%', // 可选 比率 thousandFormatNum: true // 可选 数值是否千分位格式化 默认为false }], // 数据 option: { title: { text: '' } }, // 可选 echarts 参数配置 seriesOpts: { radius: ['50%', '60%'], center: ['30%', '50%'], avoidLabelOverlap: false, label: { show: false, position: 'center', color: '#B5D9FF', formatter: ['{title|{c0}}', '{value|{b0}}'].join('\n'), fontSize: 14, fontWeight: 600, rich: { title: { color: '#ffffff', fontSize: 30, fontWeight: 600, lineHeight: 66 } } }, emphasis: { label: { show: true } } } // 饼图series配置 }; // 图表颜色 const getColor = data => { let startColor = ['28, 184, 255', '255, 191, 70', '0, 203, 141', '72, 249, 253', '255, 242, 92', '108, 96, 253']; let endColor = ['181, 218, 252', '253, 222, 165', '124, 255, 215', '207, 254, 255', '255, 252, 222', '191, 186, 255']; if (data.length > startColor.length || data.length > endColor.length) { startColor = startColor.concat(startColor.slice(0, data.length - startColor.length)); endColor = endColor.concat(endColor.slice(0, data.length - endColor.length)); } return { startColor, endColor }; }; // EXTERNAL MODULE: ./node_modules/echarts/index.js + 365 modules var echarts = __webpack_require__(5289); ;// CONCATENATED MODULE: ./node_modules/thread-loader/dist/cjs.js!./node_modules/babel-loader/lib/index.js??clonedRuleSet-82.use[1]!./node_modules/@vue/vue-loader-v15/lib/index.js??vue-loader-options!./src/package/vue-chart-pie/index.vue?vue&type=script&lang=js& let idx = 1; /* harmony default export */ var vue_chart_pievue_type_script_lang_js_ = ({ name: 'vue-chart-pie', props: { data: { type: Array, default: () => [] }, option: { type: Object, default: () => {} }, seriesOpts: { type: Object, default: () => ({}) } }, data() { return { myChart: null, chartId: '', deepAssign: utils/* deepAssign */.n }; }, computed: { hasData() { return this.data.length; }, baseLabel() { return { show: false, position: 'center', color: '#B5D9FF', formatter: ['{title|{c0}}', '{value|{b0}}'].join('\n'), fontSize: 14, fontWeight: 600, rich: { title: { color: '#ffffff', fontSize: 30, fontWeight: 600, lineHeight: 66 } } }; }, baseSeries() { return { type: 'pie', radius: ['50%', '60%'], center: ['30%', '50%'], avoidLabelOverlap: false, label: this.baseLabel, emphasis: { label: { show: true } } }; }, // 默认图例 defaultLegend() { const legend = { orient: 'vertical', right: '5%', top: '30%', textStyle: { color: 'rgba(181, 217, 255, 0.8)', lineHeight: 20, rich: { name: { fontSize: 14 }, value: { color: '#F5FAFF', fontSize: 12 } } }, formatter: name => { const data = this.data.find(item => { return item.name === name; }); const { value, ratio, thousandFormatNum } = data; const num = thousandFormatNum ? (0,utils/* thousandFormat */.P)(value) : value; let content = `{name|${name}} {value|${num}}`; if (ratio) { content += ` {value|${ratio}}`; } return content; } }; return legend; }, // 参数配置 opts() { const defaultOpts = { legend: this.defaultLegend }; return this.deepAssign(defaultOpts, this.option); } }, watch: { data() { this.$nextTick(() => { this.setChatOption(); }); } }, created() { this.chartId = `vChart_pie_${idx++}`; }, mounted() { this.setChatOption(); }, methods: { initChart() { const dom = document.getElementById(this.chartId); if (!dom) { return; } this.myChart = echarts/* init */.S1(dom); }, handleData() { const { data } = this; const { startColor, endColor } = getColor(data); const RealData = []; const borderData = []; const legendData = []; let total = 0; data.map(item => { // total += Number(item.value) RealData.push(JSON.parse(JSON.stringify(item))); borderData.push(JSON.parse(JSON.stringify(item))); legendData.push({ name: item.name + item.value }); }); total = (0,utils/* thousandFormat */.P)(total); RealData.map((item, index) => { item.itemStyle = { color: { type: 'linear', x: 0, y: 0, x2: 0, y2: 1, colorStops: [{ offset: 0, color: `rgba(${startColor[index]}, 1)` // 0% 处的颜色 }, { offset: 1, color: `rgba(${endColor[index]}, 1)` // 100% 处的颜色 }], globalCoord: false