tm-echarts.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. <template>
  2. <view class="canvasId-wk">
  3. <!-- #ifdef H5 || APP -->
  4. <canvas
  5. :style="{
  6. width: w,
  7. height: h
  8. }"
  9. v-if="cid"
  10. class="ec-canvas"
  11. :id="cid"
  12. :canvasId="cid"
  13. @touchstart="touchStart"
  14. @touchmove="touchMove"
  15. @touchend="touchEnd"
  16. @error="$emit('error',$event)"
  17. ></canvas>
  18. <!-- #endif -->
  19. <!-- #ifndef MP-WEIXIN || H5 || APP || MP-ALIPAY -->
  20. <canvas
  21. :style="{
  22. width: w,
  23. height: h
  24. }"
  25. v-if="canvasId"
  26. class="ec-canvas"
  27. id="ec-canvas"
  28. canvasId="ec-canvas"
  29. @touchstart="touchStart"
  30. @touchmove="touchMove"
  31. @touchend="touchEnd"
  32. @error="$emit('error',$event)"
  33. ></canvas>
  34. <!-- #endif -->
  35. <!-- #ifdef MP-WEIXIN || MP-ALIPAY-->
  36. <canvas
  37. :style="{
  38. width: w,
  39. height: h
  40. }"
  41. v-if="canvasId"
  42. type="2d"
  43. class="ec-canvas"
  44. id="ec-canvas"
  45. canvasId="ec-canvas"
  46. @touchstart="touchStart"
  47. @touchmove="touchMove"
  48. @touchend="touchEnd"
  49. @error="$emit('error',$event)"
  50. ></canvas>
  51. <!-- #endif -->
  52. </view>
  53. </template>
  54. <script>
  55. /**
  56. * Echart图表
  57. * @param {Number|String} width = [] 默认100%,纯数字时,单位为rpx
  58. * @param {Number|String} height = [] 默认500,纯数字时,单位为rpx,不允许百分比。
  59. * @param {Object} echarts = [] 默认null,百度echart.js插件,默认可以使用本库自带,详见文档。
  60. * @param {Function} init 图表初始化后执行触发事件返回{width,height,chart}
  61. * @param {Function} error 出错时触发。
  62. */
  63. import WxCanvas from '@/tm-vuetify/tool/function/uni-echarts-canvas.js';
  64. import * as echarts from '@/tm-vuetify/tool/function/echarts.min.js';
  65. function wrapTouch(e) {
  66. for (let i = 0; i < e.mp.touches.length; i += 1) {
  67. const touch = e.mp.touches[i];
  68. touch.offsetX = touch.x;
  69. touch.offsetY = touch.y;
  70. }
  71. return e;
  72. }
  73. function compareVersion(v1, v2) {
  74. v1 = v1.split('.');
  75. v2 = v2.split('.');
  76. const len = Math.max(v1.length, v2.length);
  77. while (v1.length < len) {
  78. v1.push('0');
  79. }
  80. while (v2.length < len) {
  81. v2.push('0');
  82. }
  83. for (let i = 0; i < len; i++) {
  84. const num1 = parseInt(v1[i]);
  85. const num2 = parseInt(v2[i]);
  86. if (num1 > num2) {
  87. return 1;
  88. } else if (num1 < num2) {
  89. return -1;
  90. }
  91. }
  92. return 0;
  93. }
  94. export default {
  95. name:"tm-echarts",
  96. props: {
  97. width: {
  98. type: String | Number,
  99. default: '100%'
  100. },
  101. height: {
  102. type: String | Number,
  103. default: '500'
  104. },
  105. canvasId: {
  106. type: String,
  107. default: 'ec-canvas'
  108. },
  109. lazyLoad: {
  110. type: Boolean,
  111. default: false
  112. },
  113. disableTouch: {
  114. type: Boolean,
  115. default: false
  116. },
  117. throttleTouch: {
  118. type: Boolean,
  119. default: false
  120. }
  121. },
  122. data() {
  123. return {
  124. echarts,
  125. cid:'ec-canvas'
  126. };
  127. },
  128. created() {
  129. this.cid = this.$tm.guid();
  130. },
  131. destroyed() {
  132. try{
  133. this.echarts=null;
  134. this.chart.clear()
  135. this.chart = null;
  136. }catch(e){
  137. //TODO handle the exception
  138. }
  139. },
  140. computed: {
  141. w: function() {
  142. if (this.width == 0 || this.width == '') {
  143. return '100%';
  144. }
  145. let reg = /(vw|vh|rem|em|\%|upx|rpx|auto|px)/g;
  146. if (reg.test(this.width)) {
  147. return this.width;
  148. }
  149. return this.width + 'rpx';
  150. },
  151. h: function() {
  152. let reg = /(vw|vh|rem|em|\%|upx|rpx|auto|px)/g;
  153. if (reg.test(this.height)) {
  154. return this.height;
  155. }
  156. return this.height + 'rpx';
  157. }
  158. },
  159. mounted() {
  160. if (!this.echarts) {
  161. console.warn('未引用echarts');
  162. return;
  163. }
  164. if (!this.lazyLoad) {
  165. this.$nextTick(function() {
  166. try{
  167. this.init();
  168. }catch(e){
  169. //TODO handle the exception
  170. console.error("echarts错误提醒:",e)
  171. }
  172. });
  173. }
  174. },
  175. methods: {
  176. //初始化
  177. init() {
  178. // #ifdef MP-WEIXIN
  179. const version = wx.version.version.split('.').map(n => parseInt(n, 10));
  180. const isValid = version[0] > 1 || (version[0] === 1 && version[1] > 9) || (version[0] === 1 && version[1] === 9 && version[2] >= 91);
  181. if (!isValid) {
  182. console.error(
  183. '微信基础库版本过低,需大于等于 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'
  184. );
  185. return;
  186. }
  187. // #endif
  188. let canvasId = this.canvasId;
  189. // #ifdef H5 || APP-PLUS || APP-VUE
  190. canvasId = this.cid;
  191. // #endif
  192. // #ifndef MP-WEIXIN || MP-ALIPAY
  193. this.ctx = uni.createCanvasContext(canvasId, this);
  194. const canvas = new WxCanvas(this.ctx, canvasId, false);
  195. this.echarts.setCanvasCreator(() => canvas);
  196. const query = uni.createSelectorQuery().in(this);
  197. query.select(`#${canvasId}`)
  198. .boundingClientRect(res => {
  199. if (!res) {
  200. setTimeout(() => this.init(), 100);
  201. return;
  202. }
  203. const { width, height } = res;
  204. const canvasDpr = uni.getSystemInfoSync().pixelRatio
  205. this.chart = this.echarts.init(canvas, null, {
  206. width: width,
  207. height: height
  208. });
  209. canvas.setChart(this.chart);
  210. const { handler } = this.chart.getZr();
  211. this.handler = handler;
  212. this.processGesture = handler.proxy.processGesture || (() => {});
  213. this.$emit('init', {
  214. width: res.width,
  215. height: res.height,
  216. chart: this.chart
  217. });
  218. })
  219. .exec();
  220. // #endif
  221. // #ifdef MP-WEIXIN || MP-ALIPAY
  222. const query = uni.createSelectorQuery().in(this)
  223. query
  224. .select('.ec-canvas')
  225. .fields({ node: true, size: true })
  226. .exec(res => {
  227. const canvasNode = res[0].node
  228. this.canvasNode = canvasNode
  229. const canvasDpr = uni.getSystemInfoSync().pixelRatio
  230. const canvasWidth = res[0].width
  231. const canvasHeight = res[0].height
  232. const ctx = canvasNode.getContext('2d')
  233. const canvas = new WxCanvas(ctx, canvasId, true,canvasNode);
  234. this.echarts.setCanvasCreator(() => {
  235. return canvas
  236. })
  237. this.chart = this.echarts.init(canvas, null, {
  238. width: canvasWidth,
  239. height: canvasHeight,
  240. devicePixelRatio:canvasDpr
  241. });
  242. canvas.setChart(this.chart);
  243. const { handler } = this.chart.getZr();
  244. this.handler = handler;
  245. this.processGesture = handler.proxy.processGesture || (() => {});
  246. this.$emit('init', {
  247. width: canvasWidth,
  248. height: canvasHeight,
  249. chart: this.chart
  250. });
  251. })
  252. // #endif
  253. },
  254. //配置图表数据
  255. setOption(dJson) {
  256. if (!this.chart){
  257. uni.$tm.toast("chart未初始化")
  258. return false;
  259. }
  260. this.chart.setOption({...dJson},{notMerge:true});
  261. return true;
  262. },
  263. //获取图表对象。
  264. getChart(FunName,arg){
  265. if (!this.chart){
  266. uni.$tm.toast("chart未初始化")
  267. return false;
  268. }
  269. return this.chart;
  270. },
  271. resize(){
  272. let t = this;
  273. return new Promise((res,rej)=>{
  274. if (!t.chart){
  275. uni.$tm.toast("chart未初始化")
  276. rej(false);
  277. return false;
  278. }
  279. let canvasId = t.canvasId;
  280. // #ifdef H5 || APP-PLUS || APP-VUE
  281. canvasId = t.cid;
  282. // #endif
  283. const query = uni.createSelectorQuery().in(t);
  284. query.select(`.canvasId-wk`)
  285. .boundingClientRect(op => {
  286. const { width, height } = op;
  287. t.chart.resize({width:width,height:height})
  288. res(true);
  289. }).exec()
  290. })
  291. },
  292. canvasToTempFilePath(opt) {
  293. const { canvasId } = this;
  294. this.ctx.draw(true, () => {
  295. wx.canvasToTempFilePath({
  296. canvasId,
  297. ...opt
  298. });
  299. });
  300. },
  301. touchStart(e) {
  302. const { disableTouch, chart } = this;
  303. if (disableTouch || !chart || !e.mp.touches.length) return;
  304. const touch = e.mp.touches[0];
  305. this.handler.dispatch('mousedown', {
  306. zrX: touch.x,
  307. zrY: touch.y
  308. });
  309. this.handler.dispatch('mousemove', {
  310. zrX: touch.x,
  311. zrY: touch.y
  312. });
  313. this.processGesture(wrapTouch(e), 'start');
  314. },
  315. touchMove(e) {
  316. const { disableTouch, throttleTouch, chart, lastMoveTime } = this;
  317. if (disableTouch || !chart || !e.mp.touches.length) return;
  318. if (throttleTouch) {
  319. const currMoveTime = Date.now();
  320. if (currMoveTime - lastMoveTime < 240) return;
  321. this.lastMoveTime = currMoveTime;
  322. }
  323. const touch = e.mp.touches[0];
  324. this.handler.dispatch('mousemove', {
  325. zrX: touch.x,
  326. zrY: touch.y
  327. });
  328. this.processGesture(wrapTouch(e), 'change');
  329. },
  330. touchEnd(e) {
  331. const { disableTouch, chart } = this;
  332. if (disableTouch || !chart) return;
  333. const touch = e.mp.changedTouches ? e.mp.changedTouches[0] : {};
  334. this.handler.dispatch('mouseup', {
  335. zrX: touch.x,
  336. zrY: touch.y
  337. });
  338. this.handler.dispatch('click', {
  339. zrX: touch.x,
  340. zrY: touch.y
  341. });
  342. this.processGesture(wrapTouch(e), 'end');
  343. }
  344. }
  345. };
  346. </script>
  347. <style scoped>
  348. .ec-canvas {
  349. width: 100%;
  350. height: 375rpx;
  351. }
  352. </style>