ecomfe / echarts-for-weixin

基于 Apache ECharts 的微信小程序图表库
BSD 3-Clause "New" or "Revised" License
7.07k stars 1.58k forks source link

在uni-app中编译到微信小程序如何使用echarts-for-weixin?希望得到答复~ #572

Open bymomo opened 4 years ago

bymomo commented 4 years ago

提问前应该做的事

请确保提问前做了以下事,将完成的项目的 [] 改为 [x]

需提供的信息

将符合项的 [] 改为 [x],并补充需要的信息:

简单描述问题:

echarts-for-weixin示例代码是可以在微信小程序上运行的,但是我使用的是uni-app编译到微信小程序,我目前也只是需要兼容的微信小程序端即可。 但是,根据把示例代码上的代码粘贴下来,无法成功运行。 问题1,绑定到组件ec属性上的对象里面的onInit传function,在组件内部接收不到。 ec: { name: 1, ces: '2', onInit: function() { console.log('回调'); } }, 为了解决问题1,我改了ec-canvas.js组件内的js,通过调用父组件办法来调用到了onInit函数,于是产生了问题2:是echarts的setOption办法调用了createElement办法,而小程序上是没dom操作的 thirdScriptError Cannot read property 'createElement' of undefined;at SelectorQuery callback function TypeError: Cannot read property 'createElement' of undefined

预期效果:

希望姐姐能提供uni-app使用echarts-for-weixin的示例代码 (如有需要请提供预期的图)

实际效果:

暂无 (如有需要请提供截图)

复现环境:

bymomo commented 4 years ago

我琢磨了1天了,接近崩溃中...期望得到答复。谢谢!!!

Ovilia commented 4 years ago

@bymomo 能给我科普下 uni-app 的原理么?微信小程序 ECharts 的实现,本质上就是对微信非标准的 Canvas 接口做了一层兼容。

bymomo commented 4 years ago

@bymomo 能给我科普下 uni-app 的原理么?微信小程序 ECharts 的实现,本质上就是对微信非标准的 Canvas 接口做了一层兼容。

目前我也不知道uni-app技术原理,它的api跟微信小程序是一致的。具体你可以看下官网介绍 uniapp官网 目前市面上的跨端开发框架就uni-app和taro比较热门,我看了issues也有人提问uniapp,taro如何使用echarts的,没得到回复。 我觉得只需要编译到微信小程序端,按理来说是应该兼容和可实现的。 最后还是希望能提供下上述的两个框架的示例程序吧,毕竟比较热门。

Ovilia commented 4 years ago

我没有精力再维护两个额外的框架,如果社区有人感兴趣的话,希望能有人能带头做一下这个事。

Zhuyi731 commented 4 years ago

我已经将组件和部分示例提交到我的git。
如何在uni-app中使用echarts 希望作者能po个链接到readme上。 taro的 taro-echarts

LiangWeiH commented 4 years ago

我已经将组件和部分示例提交到我的git。 如何在uni-app中使用echarts 希望作者能po个链接到readme上。 taro的 taro-echarts

@bymomo 能给我科普下 uni-app 的原理么?微信小程序 ECharts 的实现,本质上就是对微信非标准的 Canvas 接口做了一层兼容。

目前我也不知道uni-app技术原理,它的api跟微信小程序是一致的。具体你可以看下官网介绍 uniapp官网 目前市面上的跨端开发框架就uni-app和taro比较热门,我看了issues也有人提问uniapp,taro如何使用echarts的,没得到回复。 我觉得只需要编译到微信小程序端,按理来说是应该兼容和可实现的。 最后还是希望能提供下上述的两个框架的示例程序吧,毕竟 楼主解决了吗?

JX-Zhuang commented 4 years ago

我已经将组件和部分示例提交到我的git。 如何在uni-app中使用echarts 希望作者能po个链接到readme上。 taro的 taro-echarts

不支持新版的 taro

Zhuyi731 commented 4 years ago

我已经将组件和部分示例提交到我的git。 如何在uni-app中使用echarts 希望作者能po个链接到readme上。 taro的 taro-echarts

不支持新版的 taro 试试这个 https://github.com/WsmDyj/echarts-for-taro

huangzx3 commented 3 years ago

我已经将组件和部分示例提交到我的git。 如何在uni-app中使用echarts 希望作者能po个链接到readme上。tarotaro-echarts

以回调函数为参数无效怎么解决呢?试了很多方式没办法解决

Zenquan commented 3 years ago

我在用uniapp做小程序也遇到了这个问题,找问题的 issue 和谷歌,都没法解决,初步猜测是 因为document 在 uniapp 中没有定义。

但是不知道问题根源在哪里,所以苦思好几天,后来看到 mpvue-chartsecharts.init之前有一行 `echarts.setCanvasCreator(() => canvas)`` 发现我没有在 init 之前加这行,加完之后就正常了。

去 echarts 看了源码终于明白了,原来 setCanvasCreator 的作用是是引入 canvas 环境,再触发创建 canvas 的相关方法。证明我之前猜测没有 document 是对的,正好 与报错信息符合。

备注:setCanvasCreator的作用引用9727中Ovilia大佬的话: 它用于类似于HTML Canvas的环境,但并不完全相同

Memoyu commented 3 years ago

我在用uniapp做小程序也遇到了这个问题,找问题的 issue 和谷歌,都没法解决,初步猜测是 因为document 在 uniapp 中没有定义。

但是不知道问题根源在哪里,所以苦思好几天,后来看到 mpvue-chartsecharts.init之前有一行 `echarts.setCanvasCreator(() => canvas)`` 发现我没有在 init 之前加这行,加完之后就正常了。

去 echarts 看了源码终于明白了,原来 setCanvasCreator 的作用是是引入 canvas 环境,再触发创建 canvas 的相关方法。证明我之前猜测没有 document 是对的,正好 与报错信息符合。

备注:setCanvasCreator的作用引用9727中Ovilia大佬的话: 它用于类似于HTML Canvas的环境,但并不完全相同

听君一席话,少熬一天夜!感谢大佬! 虽然说问题点不一样,但是根源一样,准备洗澡睡觉!

EightDoor commented 2 years ago

我做了集成了,uni-app vite、vue3,需要的可以参考一下 地址

puluomia22 commented 2 years ago

根据前面提到的内容这里整合补充下:

1.两个问题直接解决方法如下

// my.vue
<template>
...
    <ec-canvas :ec="{ onInit: initChart }"> </ec-canvas> 
...
</template>
<script>

import * as echarts from "@/wxcomponents/ec-canvas/echarts"
var g_chart = null
export default {
    ...
    methods:{
        initChart() {
            echarts.setCanvasCreator(() => canvas)
            const chart = echarts.init(canvas, null, {
                width: width,
                height: height,
                devicePixelRatio: dpr 
            });
            canvas.setChart(chart);
            g_chart = chart
            return chart
        },
        myfun() {
            g_chart.setOption({...})
        }
    }
    ...
}
</script>

2. 直接原因

uni-app 下 my.vue 和 ec-canvas.js 里 import * as echarts from "..." 导出的 echarts 不是同一个对象.
虽然在ec-canvas.js 组件初始化时已经内部调用setCanvasCreator(()=>{return canvas}) 替换掉了 document.createElement ,但是 我们的my.vue 调用echarts不是同一个, 还是会报错,需要显式再调用一次 setCanvasCreator 来替换成微信提供的canvas

3. 思路

问题1
使用 :ec="{onInit: initChart}" 直接传递是可以的, 这个方法我是尝试出来的, 有对组件传值原理比较熟悉的同学可以后面再补充解释下。

问题2 echarts.js 里的报错 "Cannot read property 'createElement' of undefined" 对应的代码段是

   // echarts.js

   var createCanvas = function () {
    return methods.createCanvas();
  };

  methods.createCanvas = function () {
    return document.createElement('canvas'); // 报错的地方
  };

  ...
  function setCanvasCreator(creator) {
    $override('createCanvas', creator);
  }

  function $override(name, fn) {
    methods[name] = fn;
  }

这个函数是用来创建Canvas对象的,echarts 是在这个返回的canvas对象上进行绘图的。 因为小程序里是提供DOM对象(小程序和普通浏览器的区别),所有无法通过 doucment.createElement来创建Canvas对象,于是报错了。

再看下 ec-canvas 组件的初始化代码

   // ec-canvas.js  InitByNewWaay 
    const canvas = new WxCanvas(ctx, this.data.canvasId, true, canvasNode)
    echarts.setCanvasCreator(() => {
        return canvas
    })
    ...
    // 这里的onInit 就是我们父组件 :ec="{onInit: initChart}" 传递进来的初始化函数
    this.chart = this.data.ec.onInit(canvas, canvasWidth, canvasHeight, canvasDpr)

从代码中可以知道 ec-canvas.js 组件初始化大致流程是:

init()-->initByNewWay()-->echarts.setCanvasCreator()-->initChart()

结合上面 echarts.js 里的 setCanvasCreator, $override 可以看到, 我们的initChart 是在最后面才被调用的, 此时echarts.js 里的 createCanvas 函数应该已经被替换成 ()=>{return canvas}, createCanvas内部实际调用的函数应该是 ()=>{return canvas} 才对啊,怎么还是doucment.createElement? 且整个echart.js 只有setCanvasCreator这个地方对methods.createCanvas这个函数有替换的操作。 难道还有其它运行时bug,把methods.createcanvas给改了, 真奇怪!!!

于是在猜想ec-canvas.js 里访问的 echarts 对象和 我们自己代码里的 initChart 访问的 echarts对象有没可能不是同一个? 两个地方加个万能的log把echarts对象打印出来对比看下差异. 因为js 没有内置方法可以打印对象唯一内存id? 添加一个随机数来标识。 在echarts.js 最后一行把添加两个导出

    // echarts.js

    exports.env = env;
    exports.Model = Model;
    exports.Axis = Axis;
    exports.innerDrawElementOnCanvas = brushSingle;
    exports.Amethods = methods; // 新增导出
    exports.Arandomid = Math.random(); // 新增导出
});

ec-canvas.js 组件和我们自己的initChart 函数里添加打印

   // ec-canvas.js  InitByNewWaay 
    const canvas = new WxCanvas(ctx, this.data.canvasId, true, canvasNode)
    echarts.setCanvasCreator(() => {
        return canvas
    })
   console.log("echarts in ec-canvas.js = ", echarts) // 打印echarts
    // my.vue
    export default {
        methods: {
            initChart(canvas, width, height, dpr) {
            console.log("echarts in my.vue = ", echarts) // 打印echarts
            const chart = echarts.init(canvas, null, {
                width: width,
                ...
            }
    }

下面是uniapp编译后到微信开发者工具上的输出结果。 1652443572 1652443572(1)

可以看到Arandomid 是不一样的, 验证了是两个不同的echarts.

同样的方法对比测试了不使用 unippp, 直接在原生微信小程序上使用ec-canvas 组件,打印结果证明 ec-canvas.js, my.js import 两处导入的 echarts 是同一个, 所以使用时不会报错。

打开uniapp编译my.vue后的my.js, 可以看到my.js 对echarts.js的导入代码是这样的。

var echarts = _interopRequireWildcard(__webpack_require__(/*! @/wxcomponents/ec-canvas/echarts */ 30));

所以下一步猜测是 uniapp把my.vue 编译成my.js时这里_interopRequireWildcard(webpack_require__ 引起的问题,到这里我就没有再找下去了, 有对uniapp或webapck比较熟悉的朋友可以补充下,_interopRequireWildcard(webpack_require__ 和直接 import * as echarts from '' 有什么区别? 或是微信小程序对底层对import作了改动?

xbmlz commented 1 year ago

https://github.com/xbmlz/echarts-for-uniapp Apache ECharts 的uni-app版本, 支持Vue 2/3.