uni-ec-canvas.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. <template>
  2. <canvas type="2d" v-if="isUseNewCanvas" class="ec-canvas" :canvas-id="canvasId" @init="init" @touchstart="touchStart"
  3. @touchmove="touchMove" @touchend="touchEnd">
  4. </canvas>
  5. <canvas v-else class="ec-canvas" :canvas-id="canvasId" @init="init" @touchstart="touchStart" @touchmove="touchMove"
  6. @touchend="touchEnd">
  7. </canvas>
  8. </template>
  9. <script>
  10. import WxCanvas from "./wx-canvas";
  11. import * as echarts from "./echarts";
  12. let ctx;
  13. function wrapTouch(event) {
  14. for (let i = 0; i < event.touches.length; ++i) {
  15. const touch = event.touches[i];
  16. touch.offsetX = touch.x;
  17. touch.offsetY = touch.y;
  18. }
  19. return event;
  20. }
  21. export default {
  22. props: {
  23. canvasId: {
  24. type: String,
  25. default: () => {
  26. return "ec-canvas";
  27. }
  28. },
  29. ec: {
  30. type: Object
  31. },
  32. forceUseOldCanvas: {
  33. type: Boolean,
  34. value: false
  35. }
  36. },
  37. data() {
  38. return {
  39. $curChart: {},
  40. toHandleList: [],
  41. isUseNewCanvas: true
  42. };
  43. },
  44. watch: {
  45. "ec.option": {
  46. deep: true,
  47. handler(val, oldVal) {
  48. this.setOption(val);
  49. }
  50. }
  51. },
  52. onReady: function() {
  53. if (!this.ec) {
  54. console.warn(
  55. '组件需绑定 ec 变量,例:<ec-canvas id="mychart-dom-bar" ' +
  56. 'canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>'
  57. );
  58. return;
  59. }
  60. if (!this.ec.lazyLoad) {
  61. this.init();
  62. }
  63. },
  64. methods: {
  65. compareVersion(v1, v2) {
  66. v1 = v1.split(".");
  67. v2 = v2.split(".");
  68. const len = Math.max(v1.length, v2.length);
  69. while (v1.length < len) {
  70. v1.push("0");
  71. }
  72. while (v2.length < len) {
  73. v2.push("0");
  74. }
  75. for (let i = 0; i < len; i++) {
  76. const num1 = parseInt(v1[i]);
  77. const num2 = parseInt(v2[i]);
  78. if (num1 > num2) {
  79. return 1;
  80. } else if (num1 < num2) {
  81. return -1;
  82. }
  83. }
  84. return 0;
  85. },
  86. init(callback) {
  87. const version = wx.getSystemInfoSync().SDKVersion;
  88. let canUseNewCanvas = this.compareVersion(version, "2.9.0") >= 0;
  89. if (this.forceUseOldCanvas) {
  90. if (canUseNewCanvas) console.warn("开发者强制使用旧canvas,建议关闭");
  91. canUseNewCanvas = false;
  92. }
  93. this.isUseNewCanvas = canUseNewCanvas && !this.forceUseOldCanvas;
  94. if (this.isUseNewCanvas) {
  95. console.log('微信基础库版本大于2.9.0,开始使用<canvas type="2d"/>');
  96. // 2.9.0 可以使用 <canvas type="2d"></canvas>
  97. this.initByNewWay(callback);
  98. } else {
  99. const isValid = this.compareVersion(version, "1.9.91") >= 0;
  100. if (!isValid) {
  101. console.error(
  102. "微信基础库版本过低,需大于等于 1.9.91。" +
  103. "参见:https://github.com/ecomfe/echarts-for-weixin" +
  104. "#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82"
  105. );
  106. return;
  107. } else {
  108. console.warn(
  109. "建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能"
  110. );
  111. this.initByOldWay(callback);
  112. }
  113. }
  114. },
  115. initByOldWay(callback) {
  116. // 1.9.91 <= version < 2.9.0:原来的方式初始化
  117. ctx = wx.createCanvasContext(this.canvasId, this);
  118. const canvas = new WxCanvas(ctx, this.canvasId, false);
  119. const that = this
  120. echarts.setCanvasCreator(() => {
  121. return canvas;
  122. });
  123. // const canvasDpr = wx.getSystemInfoSync().pixelRatio // 微信旧的canvas不能传入dpr
  124. const canvasDpr = 1;
  125. var query = wx.createSelectorQuery().in(this);
  126. query
  127. .select(".ec-canvas")
  128. .boundingClientRect(res => {
  129. if (typeof callback === "function") {
  130. that.$curChart = callback(canvas, res.width, res.height, canvasDpr);
  131. } else if (that.ec) {
  132. that.initChart(canvas, res.width, res.height, canvasDpr)
  133. } else {
  134. that.triggerEvent("init", {
  135. canvas: canvas,
  136. width: res.width,
  137. height: res.height,
  138. devicePixelRatio: canvasDpr // 增加了dpr,可方便外面echarts.init
  139. });
  140. }
  141. })
  142. .exec();
  143. },
  144. initByNewWay(callback) {
  145. const that = this
  146. // version >= 2.9.0:使用新的方式初始化
  147. const query = wx.createSelectorQuery().in(this);
  148. query
  149. .select(".ec-canvas")
  150. .fields({
  151. node: true,
  152. size: true
  153. })
  154. .exec(res => {
  155. const canvasNode = res[0].node;
  156. const canvasDpr = wx.getSystemInfoSync().pixelRatio;
  157. const canvasWidth = res[0].width;
  158. const canvasHeight = res[0].height;
  159. const ctx = canvasNode.getContext("2d");
  160. const canvas = new WxCanvas(ctx, that.canvasId, true, canvasNode);
  161. echarts.setCanvasCreator(() => {
  162. return canvas;
  163. });
  164. if (typeof callback === "function") {
  165. that.$curChart = callback(
  166. canvas,
  167. canvasWidth,
  168. canvasHeight,
  169. canvasDpr
  170. );
  171. } else if (that.ec) {
  172. that.initChart(canvas, canvasWidth, canvasHeight, canvasDpr)
  173. } else {
  174. that.triggerEvent("init", {
  175. canvas: canvas,
  176. width: canvasWidth,
  177. height: canvasHeight,
  178. devicePixelRatio: canvasDpr
  179. });
  180. }
  181. });
  182. },
  183. setOption(val) {
  184. if (!this.$curChart || !this.$curChart.setOption) {
  185. this.toHandleList.push(val);
  186. } else {
  187. this.$curChart.setOption(val);
  188. }
  189. },
  190. canvasToTempFilePath(opt) {
  191. if (this.isUseNewCanvas) {
  192. // 新版
  193. const query = wx.createSelectorQuery().in(this);
  194. query
  195. .select(".ec-canvas")
  196. .fields({
  197. node: true,
  198. size: true
  199. })
  200. .exec(res => {
  201. const canvasNode = res[0].node;
  202. opt.canvas = canvasNode;
  203. wx.canvasToTempFilePath(opt);
  204. });
  205. } else {
  206. // 旧的
  207. if (!opt.canvasId) {
  208. opt.canvasId = this.canvasId;
  209. }
  210. ctx.draw(true, () => {
  211. wx.canvasToTempFilePath(opt, this);
  212. });
  213. }
  214. },
  215. touchStart(e) {
  216. if (this.ec.stopTouchEvent) {
  217. e.preventDefault();
  218. e.stopPropagation();
  219. return;
  220. }
  221. this.$emit("touchstart", e);
  222. if (this.$curChart && e.touches.length > 0) {
  223. var touch = e.touches[0];
  224. var handler = this.$curChart.getZr().handler;
  225. if (handler) {
  226. handler.dispatch("mousedown", {
  227. zrX: touch.x,
  228. zrY: touch.y
  229. });
  230. handler.dispatch("mousemove", {
  231. zrX: touch.x,
  232. zrY: touch.y
  233. });
  234. handler.processGesture(wrapTouch(e), "start");
  235. }
  236. }
  237. },
  238. touchMove(e) {
  239. if (this.ec.stopTouchEvent) {
  240. e.preventDefault();
  241. e.stopPropagation();
  242. return;
  243. }
  244. this.$emit("touchmove", e);
  245. if (this.$curChart && e.touches.length > 0) {
  246. var touch = e.touches[0];
  247. var handler = this.$curChart.getZr().handler;
  248. if (handler) {
  249. handler.dispatch("mousemove", {
  250. zrX: touch.x,
  251. zrY: touch.y
  252. });
  253. handler.processGesture(wrapTouch(e), "change");
  254. }
  255. }
  256. },
  257. touchEnd(e) {
  258. if (this.ec.stopTouchEvent) {
  259. e.preventDefault();
  260. e.stopPropagation();
  261. return;
  262. }
  263. this.$emit("touchend", e);
  264. if (this.$curChart) {
  265. const touch = e.changedTouches ? e.changedTouches[0] : {};
  266. var handler = this.$curChart.getZr().handler;
  267. if (handler) {
  268. handler.dispatch("mouseup", {
  269. zrX: touch.x,
  270. zrY: touch.y
  271. });
  272. handler.dispatch("click", {
  273. zrX: touch.x,
  274. zrY: touch.y
  275. });
  276. handler.processGesture(wrapTouch(e), "end");
  277. }
  278. }
  279. },
  280. initChart(canvas, width, height, canvasDpr) {
  281. this.$curChart = echarts.init(canvas, null, {
  282. width: width,
  283. height: height,
  284. devicePixelRatio: canvasDpr
  285. });
  286. canvas.setChart(this.$curChart);
  287. this.$curChart.setOption(this.ec.option);
  288. }
  289. }
  290. };
  291. </script>
  292. <style lang="scss">
  293. .ec-canvas {
  294. width: 100%;
  295. height: 100%;
  296. display: block;
  297. }
  298. </style>