你的浏览器不支持canvas

让我们携手共创奇迹!

UE图表-ECharts

Date: Author: LBD

本文章采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。转载请注明来自WindCrazy

这是一篇关于使用ECharts制作UE图表的一些知识

0、前言

在UE中想要实现一个好看可交互的图表实现起来非常的麻烦,但是有一种办法可以将网页在UE的UI中显示,借助这个办法就可以配合知名度很高的ECharts实现直观,交互丰富,可高度个性化定制的数据可视化图表。

ECharts网页:Apache ECharts

那么接下来我要做到的效果是

  1. 在UE中显示简单折线图
  2. 按键传递UE产生的数据给html,然后此UI同步数据更新折线图
  3. 与html交互,产生的数据发给UE并log打印出来

1、试用ECharts

先快速入门一下,然后再在UE中使用。

创建文件夹

HTML |-js | |-js文件 html文件

下载JS库

下载方式:下载

我使用的是在线定制,我把我需要的勾上(chart: Bar、Line、Radar, coordinate systems: Grid、Polar, 默认, others: 只勾选工具集)然后下载。

将下载好的js库放入js文件夹 然后新建一个html

<!DOCTYPE html>
<html lang="en" style="height: 100%">
<head>
 <meta charset ="utf-8">
</head>
<body style="height: 100%; margin: 0">
  <!--容器,后面脚本会根据此容器id放入echart-->
  <div id="container" style="height: 100%"></div>
  
  <!--引入js库-->
  <script src='js/echarts.js'></script>
  <script type="text/javascript">
    //初始化ECharts实例
    var dom = document.getElementById('container');
    var myChart = echarts.init(dom);
    // ECharts基础配置:折线图
    var option;
    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'
        }
      ]
    };

	//显示
    myChart.setOption(option);

    // 窗口大小自适应
    window.onresize = function () {
      myChart.resize();
    };
  </script>
</body>
</html>

双击后即可看到一条普通的折线图,此示例参考自简单折线图,使用起来非常简单,还有很生动且完善的文档,比如快速上手的使用手册,所有的配置项和很多示例

2、接入UE

刚才用过ECharts之后,很明显,他只是一个方便在网页写图表的库和UE没有一点关系,不过之前也说了,有一种办法可以将网页显示在UI上,这个工具我用的是Web UI,他提供免费下载渠道,功能是在UI中创建基于网页的UI并且JavaScript与UE相互通信等。

下载好以后会有两个文件夹:WebUIJsonLibrary,将这两个文件夹放到引擎插件的Marketplace下,打开项目后开启这俩插件,创建Widget Blueprint就会发现Common栏多了一个Web Interface,拖进来后如图所示填写Web Interface实例的LoadFile函数的参数,文件名是你创建的,现在将他Add to viewport就已经可以看到你上一章节创建的折线图了

当然,现阶段UE与这个UI的交互仅仅是鼠标和html的交互,这远远达不到想要的效果

挂载函数,绑定委托

要想进行与UE的交互还需要在html里写一些东西,将代码放到第一章写的script下方,不然myChart这个变量还没初始化

<script>
  // ===================== 必加:UE WebUI 通信助手函数 =====================
  if (typeof ue != "object" || typeof ue.interface != "object") {
    if (typeof ue != "object") ue = {};
    ue.interface = {};
    ue.interface.broadcast = function (name, data) {
      if (typeof name != "string") return;
      var args = [name, ""];
      if (typeof data != "undefined") args[1] = data;
      var hash = encodeURIComponent(JSON.stringify(args));
      if (
        typeof history == "object" &&
        typeof history.pushState == "function"
      ) {
        history.pushState({}, "", "#" + hash);
        history.pushState({}, "", "#" + encodeURIComponent("[]"));
      } else {
        document.location.hash = hash;
        document.location.hash = encodeURIComponent("[]");
      }
    };
  }
  // 全局ue5函数,简化调用:ue5(事件名, 数据)
  var ue5 = ue.interface.broadcast;
</script>
<script>
  // ===================== 供UE调用的【数据更新函数】(UE→ECharts) =====================
  // 挂载到ue.interface对象上,UE可通过Call节点调用此函数,参数为JSON格式的图表数据
  ue.interface.updateEChartsData = function (chartData) {
    // chartData是UE传递的JSON对象,直接更新ECharts配置
    myChart.setOption({
      series: [
        {
          data: chartData[0],type: 'line'
        }
      ],
    });
      
    // 可选:将更新结果回传给UE(前端→UE)
    var res = { status: chartData, time: new Date().getTime() };
    ue5("ECharts_Updated", JSON.stringify(res));
  };
    
  // ===================== ECharts交互事件→UE 数据发送(核心:ECharts→UE) =====================
  // 点击ECharts图表,将点击的节点数据发送给UE
  myChart.on("click", function (params) {
    // 构造要发送给UE的JSON数据
    var clickData = {
      chartType: "line",
      seriesName: params.seriesName,
      dataIndex: params.dataIndex,
      value: params.value,
      name: params.name,
    };
    // 通过ue5()发送给UE,事件名:ECharts_Click(UE端需监听此名称)
    ue5("ECharts_Click", JSON.stringify(clickData));
  });
</script>

JavaScript代码很简单,注释也写清楚了,接下来就是UE蓝图了

ECharts到UE

绑定html回调函数,就是JavaScript里的ue5(),Name就是第一个参数,Data就是第二个参数,Stringfy函数是JsonLibrary里的

然后你会发现还有一个Callback没有用到这个东西我看文档是说ue5()这个函数可以接收四个参数,但是我上方写的UE WebUI 通信助手函数只能接收两个,所以需要更改助手函数,下文所示,这下就可以了

<script>
  //==================UE WebUI 通信助手函数=====================
  ("object" != typeof ue && (ue = {}),
    (uuidv4 = function () {
      return "10000000-1000-4000-8000-100000000000".replace(
        /[018]/g,
        function (t) {
          return (
            t ^
            (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (t / 4)))
          ).toString(16);
        },
      );
    }),
    (ue5 = (function (r) {
      return "object" != typeof ue.interface ||
        "function" != typeof ue.interface.broadcast
        ? ((ue.interface = {}),
          function (t, e, n, o) {
            var u, i;
            "string" == typeof t &&
              ("function" == typeof e && ((o = n), (n = e), (e = null)),
              (u = [t, "", r(n, o)]),
              void 0 !== e && (u[1] = e),
              (i = encodeURIComponent(JSON.stringify(u))),
              "object" == typeof history &&
              "function" == typeof history.pushState
                ? (history.pushState({}, "", "#" + i),
                  history.pushState({}, "", "#" + encodeURIComponent("[]")))
                : ((document.location.hash = i),
                  (document.location.hash = encodeURIComponent("[]"))));
          })
        : ((i = ue.interface),
          (ue.interface = {}),
          function (t, e, n, o) {
            var u;
            "string" == typeof t &&
              ("function" == typeof e && ((o = n), (n = e), (e = null)),
              (u = r(n, o)),
              void 0 !== e
                ? i.broadcast(t, JSON.stringify(e), u)
                : i.broadcast(t, "", u));
          });
      var i;
    })(function (t, e) {
      if ("function" != typeof t) return "";
      var n = uuidv4();
      return (
        (ue.interface[n] = t),
        setTimeout(
          function () {
            delete ue.interface[n];
          },
          1e3 * Math.max(1, parseInt(e) || 0),
        ),
        n
      );
    })));
</script>

第三个参数传函数引用,第四个参数传销毁第三个参数的函数引用的时间默认是1秒,我真是实验下来发现,默认1秒,在UE中延迟2秒后调用Callback发现CallbackValid仍然返回true,但是函数已经无法执行,这一点需要注意

ue5("ECharts_Click", JSON.stringify(clickData), function(v){
  myChart.setOption({
  series: [
    {
      data: [4,5,v],
      type: "line",
    },
  ],
});
}, 3);//3秒

UE到ECharts

CopyFromFloatArray可以将UE的浮点数据合并到一个数组里(),Add Value可以给JSON List添加数据,在html读取就当做数组读,最后使用WebInterface调用Call,函数名就填你挂载函数的名称ue.interface.updateEChartsData中的updateEChartsData

3、其他

打包的话需要在Project Setting-Packaging-Additional Non-Asset Directories to Package添加HTML

可以不使用这种静态文件,除了Load File还有Load URL

4、我的Demo

UE_ECharts

参考

【UE4】嵌入ECharts大数据可视化图表

ECharts快速上手

Web UI

Web UI 文档


对于本文内容有问题或建议的小伙伴,欢迎提出问题