相信众多朋友们找个靠谱能跑的微信小程序echarts的demo比较费劲,各种报错,话不多说,按照流程走包你跑起来
1.下载echarts
首先博主使用的是vuecli创建的uniapp,所以可以直接npm 下载包,如果是hbuildX创建项目的话自己去官网搞个echarts.js包下来即可,下载命令如下(必须要5.2.2版本),最新版会报错,粗略看了下是因为没有用?.链式操作符导致只能在h5用
npm i echarts@5.2.2 -S
下载完成后在plugins/echarts目录下新建echarts.vue文件,代码如下
<template>
<canvas
v-if="canvasId"
:type="forceUseOldCanvas ? '' : '2d'"
class="ec-canvas"
:id="canvasId"
:canvasId="canvasId"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
>
</canvas>
</template>
<script>
import WxCanvas2 from './wx-canvas2'
import WxCanvas from './wx-canvas'
import * as echarts from 'echarts/dist/echarts.min'
// import * as echarts from './echarts.min.js'
function compareVersion (v1s, v2s) {
const v1 = v1s.split('.')
const v2 = v2s.split('.')
const len = Math.max(v1.length, v2.length)
while (v1.length < len) {
v1.push('0')
}
while (v2.length < len) {
v2.push('0')
}
for (let i = 0; i < len; i += 1) {
const num1 = parseInt(v1[i])
const num2 = parseInt(v2[i])
if (num1 > num2) {
return 1
} else if (num1 < num2) {
return -1
}
}
return 0
}
export default {
props: {
// echarts: {
// required: true,
// type: Object,
// default () {
// return null
// }
// },
forceUseOldCanvas: {
type: Boolean,
default: false
},
canvasId: {
type: String,
default: 'ec-canvas'
},
onInit: {
type: Function,
default: null
},
lazyLoad: {
type: Boolean,
default: false
},
disableTouch: {
type: Boolean,
default: false
},
throttleTouch: {
type: Boolean,
default: false
}
},
// onReady () {
// if (!echarts) {
// console.warn('组件需echarts 变量')
// return
// }
// if (!this.lazyLoad) {
// this.init()
// }
// },
// #ifdef H5
mounted () {
if (!this.lazyLoad) this.init()
},
// #endif
// #ifndef H5
onReady () {
if (!this.lazyLoad) this.init()
},
// #endif
methods: {
init (callback) {
const version = wx.getSystemInfoSync().SDKVersion
const canUseNewCanvas = compareVersion(version, '2.9.0') >= 0
this.isUseNewCanvas = canUseNewCanvas && !this.forceUseOldCanvas
if (this.forceUseOldCanvas && canUseNewCanvas) {
console.warn('开发者强制使用旧canvas,建议关闭')
}
if (this.isUseNewCanvas) {
this.initByNewWay(callback)
} else {
const isValid = compareVersion(version, '1.9.91') >= 0
if (!isValid) {
console.error(
'微信基础库版本过低,需大于等于 1.9.91。' +
'参见:https://github.com/ecomfe/echarts-for-weixin' +
'#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82'
)
} else {
console.warn(
'建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能'
)
this.initByOldWay(callback)
}
}
},
setChart (chart) {
this.chart = chart
},
initByNewWay (callback) {
// version >= 2.9.0:使用新的方式初始化
const { canvasId } = this
const query = wx.createSelectorQuery().in(this)
query
.select(`#${canvasId}`)
.fields({ node: true, size: true })
.exec(res => {
if (!res) {
setTimeout(() => this.init(), 50)
return
}
const canvasNode = res[0].node
this.canvasNode = canvasNode
const canvasDpr = wx.getSystemInfoSync().pixelRatio
// const canvasWidth = res[0].width
// const canvasHeight = res[0].height
const ctx = canvasNode.getContext('2d')
this.canvas = new WxCanvas2(ctx, canvasId, true, canvasNode)
echarts.setCanvasCreator(() => this.canvas)
setTimeout(() => {
this.$emit('onInit', {
width: res[0].width,
height: res[0].height,
canvasDpr
})
}, 50)
// if (typeof callback === 'function') {
// this.chart = callback(canvas, canvasWidth, canvasHeight, canvasDpr)
// } else if (typeof this.onInit === 'function') {
// this.chart = this.onInit(
// canvas,
// canvasWidth,
// canvasHeight,
// canvasDpr
// )
// } else {
// this.triggerEvent('init', {
// canvas,
// width: canvasWidth,
// height: canvasHeight,
// dpr: canvasDpr
// })
// }
})
},
initByOldWay (callback) {
const { canvasId } = this
this.ctx = wx.createCanvasContext(canvasId, this)
this.canvas = new WxCanvas(this.ctx, canvasId)
const query = wx.createSelectorQuery().in(this)
query
.select(`#${canvasId}`)
.boundingClientRect(res => {
if (!res) {
setTimeout(() => this.init(), 50)
return
}
this.$emit('onInit', {
width: res.width,
height: res.height
})
})
.exec()
},
touchStart (e) {
const { disableTouch, chart } = this
if (disableTouch || !chart || !e.mp.touches.length) return
const touch = e.mp.touches[0]
chart._zr.handler.dispatch('mousedown', {
zrX: touch.x,
zrY: touch.y
})
chart._zr.handler.dispatch('mousemove', {
zrX: touch.x,
zrY: touch.y
})
},
touchMove (e) {
const { disableTouch, throttleTouch, chart, lastMoveTime } = this
if (disableTouch || !chart || !e.mp.touches.length) return
if (throttleTouch) {
const currMoveTime = Date.now()
if (currMoveTime - lastMoveTime < 240) return
this.lastMoveTime = currMoveTime
}
const touch = e.mp.touches[0]
chart._zr.handler.dispatch('mousemove', {
zrX: touch.x,
zrY: touch.y
})
},
touchEnd (e) {
const { disableTouch, chart } = this
if (disableTouch || !chart) return
const touch = e.mp.changedTouches ? e.mp.changedTouches[0] : {}
chart._zr.handler.dispatch('mouseup', {
zrX: touch.x,
zrY: touch.y
})
chart._zr.handler.dispatch('click', {
zrX: touch.x,
zrY: touch.y
})
}
}
}
</script>
<style scoped>
.ec-canvas {
width: 100%;
height: 100%;
}
</style>
导入的依赖wx-canvas和wx-canvas2都在echarts.vue同级目录下
wx-canvas.js(使用的是旧canvas渲染)
export default class WxCanvas {
constructor(ctx, canvasId) {
this.ctx = ctx;
this.canvasId = canvasId;
this.chart = null;
WxCanvas.initStyle(ctx);
this.initEvent();
}
getContext(contextType) {
return contextType === '2d' ? this.ctx : null;
}
setChart(chart) {
this.chart = chart;
}
attachEvent() {
// noop
}
detachEvent() {
// noop
}
static initStyle(ctx) {
const styles = ['fillStyle', 'strokeStyle', 'globalAlpha',
'textAlign', 'textBaseAlign', 'shadow', 'lineWidth',
'lineCap', 'lineJoin', 'lineDash', 'miterLimit', 'fontSize'];
styles.forEach((style) => {
Object.defineProperty(ctx, style, {
set: (value) => {
if ((style !== 'fillStyle' && style !== 'strokeStyle')
|| (value !== 'none' && value !== null)
) {
ctx[`set${style.charAt(0).toUpperCase()}${style.slice(1)}`](value);
}
},
});
});
ctx.createRadialGradient = () => ctx.createCircularGradient(arguments);
}
initEvent() {
this.event = {};
const eventNames = [{
wxName: 'touchStart',
ecName: 'mousedown',
}, {
wxName: 'touchMove',
ecName: 'mousemove',
}, {
wxName: 'touchEnd',
ecName: 'mouseup',
}, {
wxName: 'touchEnd',
ecName: 'click',
}];
eventNames.forEach((name) => {
this.event[name.wxName] = (e) => {
const touch = e.mp.touches[0];
this.chart.getZr().handler.dispatch(name.ecName, {
zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
zrY: name.wxName === 'tap' ? touch.clientY : touch.y,
});
};
});
}
}
wx-canvas2.js(使用canvas2d渲染)
export default class WxCanvas2 {
constructor(ctx, canvasId, isNew, canvasNode) {
this.ctx = ctx;
this.canvasId = canvasId;
this.chart = null;
this.isNew = isNew
if (isNew) {
this.canvasNode = canvasNode;
}
else {
this._initStyle(ctx);
}
// this._initCanvas(zrender, ctx);
this._initEvent();
}
getContext(contextType) {
if (contextType === '2d') {
return this.ctx;
}
}
// canvasToTempFilePath(opt) {
// if (!opt.canvasId) {
// opt.canvasId = this.canvasId;
// }
// return wx.canvasToTempFilePath(opt, this);
// }
setChart(chart) {
this.chart = chart;
}
attachEvent() {
// noop
}
detachEvent() {
// noop
}
_initCanvas(zrender, ctx) {
zrender.util.getContext = function () {
return ctx;
};
zrender.util.$override('measureText', function (text, font) {
ctx.font = font || '12px sans-serif';
return ctx.measureText(text);
});
}
_initStyle(ctx) {
var styles = ['fillStyle', 'strokeStyle', 'globalAlpha',
'textAlign', 'textBaseAlign', 'shadow', 'lineWidth',
'lineCap', 'lineJoin', 'lineDash', 'miterLimit', 'fontSize'];
styles.forEach(style => {
Object.defineProperty(ctx, style, {
set: value => {
if (style !== 'fillStyle' && style !== 'strokeStyle'
|| value !== 'none' && value !== null
) {
ctx['set' + style.charAt(0).toUpperCase() + style.slice(1)](value);
}
}
});
});
ctx.createRadialGradient = () => {
return ctx.createCircularGradient(arguments);
};
}
_initEvent() {
this.event = {};
const eventNames = [{
wxName: 'touchStart',
ecName: 'mousedown'
}, {
wxName: 'touchMove',
ecName: 'mousemove'
}, {
wxName: 'touchEnd',
ecName: 'mouseup'
}, {
wxName: 'touchEnd',
ecName: 'click'
}];
eventNames.forEach(name => {
this.event[name.wxName] = e => {
const touch = e.touches[0];
this.chart.getZr().handler.dispatch(name.ecName, {
zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
zrY: name.wxName === 'tap' ? touch.clientY : touch.y
});
};
});
}
set width(w) {
if (this.canvasNode) this.canvasNode.width = w
}
set height(h) {
if (this.canvasNode) this.canvasNode.height = h
}
get width() {
if (this.canvasNode)
return this.canvasNode.width
return 0
}
get height() {
if (this.canvasNode)
return this.canvasNode.height
return 0
}
}
这样就封装好了echarts组件,然后在使用的地方再新建一个myecharts.vue
myecharts.vue(真正配置echarts配置项的地方)
<template>
<view class="echarts-wrap">
<uniappEcharts
class="ec-canvas"
@onInit="myinit"
canvasId="demo-canvas"
ref="chart1"
/>
</view>
</template>
<script>
import * as echarts from 'echarts/dist/echarts.min'
import uniappEcharts from '@/plugins/echarts/echarts.vue'
let chart1 = null
export default {
components: {
uniappEcharts
},
methods: {
// 就是返回echarts配置项的
getOptions () {
const option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line'
}
]
}
return option
},
myinit (e) {
let { width, height , canvasDpr } = e
let canvas = this.$refs.chart1.canvas
echarts.setCanvasCreator(() => canvas)
chart1 = echarts.init(canvas, null, {
width: width,
height: height,
devicePixelRatio: canvasDpr
})
canvas.setChart(chart1)
console.log(this.getOptions(),2222);
chart1.setOption(this.getOptions())
this.$refs.chart1.setChart(chart1)
}
}
}
</script>
<style>
.echarts-wrap {
width: 100%;
height: 500px;
}
</style>
随便找个html文档插入即可看到效果(如果想使用旧的canvas渲染的话,只需在uniappEcharts上添加 forceUseOldCanvas属性即可)
注意:小程序一般会限制单包2m大小,碰上这种情况自己去定制一个echarts.js就行,很简单的,小学生都会用,选自己需要的图例即可