HQChartControl.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. <template>
  2. <!-- #ifdef H5 -->
  3. <div class='kline' v-bind:id='KLineID' v-bind:style="{width: ChartWidth+'px', height: ChartHeight+'px', position: relative }" ref='kline'></div>
  4. <!-- #endif -->
  5. <!-- #ifdef MP-WEIXIN -->
  6. <canvas class="kline" v-bind:id='KLineID' type="2d"
  7. v-bind:style="{width: ChartWidth+'px', height: ChartHeight+'px'}"
  8. @touchstart="KLineTouchStart" @touchmove='KLineTouchMove' @touchend='KLineTouchEnd' />
  9. <!-- #endif -->
  10. <!-- #ifndef H5 || MP-WEIXIN -->
  11. <canvas v-bind:id='KLineID' v-bind:canvas-id='KLineID' class='kline2' v-bind:style="{width: ChartWidth+'px', height: ChartHeight+'px'}"
  12. @touchstart="KLineTouchStart" @touchmove='KLineTouchMove' @touchend='KLineTouchEnd' ></canvas>
  13. <!-- #endif -->
  14. </template>
  15. <script>
  16. /*
  17. copyright (c) 2018 jones
  18. http://www.apache.org/licenses/LICENSE-2.0
  19. 开源项目 https://github.com/jones2000/HQChart
  20. jones_2000@163.com
  21. HQChart简单的模板类
  22. */
  23. // #ifdef H5
  24. import HQChart from './umychart.uniapp.h5.js'
  25. import './umychart.resource/font/iconfont.css'
  26. import "./umychart.resource/css/tools.css"
  27. // #endif
  28. // #ifndef H5
  29. import {JSCommon} from './umychart.wechat.3.0.js'
  30. import {JSCommonHQStyle} from './umychart.style.wechat.js'
  31. import {JSConsole} from './umychart.console.wechat.js'
  32. //禁用日志
  33. JSConsole.Complier.Log=()=>{ };
  34. JSConsole.Chart.Log=()=>{ };
  35. // #endif
  36. //插件帮助函数
  37. function HQChartHelper() { }
  38. //把Vue3的markRow包装下,支持vue2
  39. HQChartHelper.MarkRaw=function(value)
  40. {
  41. return value;
  42. }
  43. // #ifdef VUE3
  44. import { markRaw } from 'vue'
  45. HQChartHelper.MarkRaw=function(value)
  46. {
  47. return markRaw(value);
  48. }
  49. // #endif
  50. function DefaultData() { }
  51. DefaultData.GetKLineOption = function ()
  52. {
  53. let data =
  54. {
  55. Type: '历史K线图',
  56. Windows: //窗口指标
  57. [
  58. {Index:"MA",Modify: false, Change: false},
  59. {Index:"VOL",Modify: false, Change: false},
  60. //{Index:"AMO",Modify: false, Change: false}
  61. /*
  62. {
  63. Index:'多线段指标',Modify: false, Change: false,
  64. API:
  65. {
  66. Name:'多线段指标',
  67. Script:null,
  68. Args:null,
  69. Url:'http://127.0.0.1:18080/api/jsindex'
  70. }
  71. }
  72. */
  73. ],
  74. IsAutoUpdate:true,
  75. IsCorssOnlyDrawKLine:true,
  76. CorssCursorTouchEnd:true,
  77. IsClickShowCorssCursor:true,
  78. CorssCursorInfo:{ Left:2, Right:2, Bottom:1, IsShowCorss:true}, //十字光标刻度设置
  79. //IsFullDraw:true,
  80. Border: //边框
  81. {
  82. Left: 1,
  83. Right: 1, //右边间距
  84. Top: 25,
  85. Bottom: 25,
  86. },
  87. KLine:
  88. {
  89. DragMode:1,
  90. Right:1, //复权 0 不复权 1 前复权 2 后复权
  91. Period:0, //周期: 0 日线 1 周线 2 月线 3 年线
  92. PageSize:6,
  93. IsShowTooltip:false,
  94. DrawType:0,
  95. DataWidth:10
  96. },
  97. KLineTitle: //K线标题栏设置
  98. {
  99. DateTimeSpace:1,
  100. PeriodSpace:1,
  101. NameSpace:1,
  102. },
  103. ExtendChart:
  104. [
  105. {Name:'KLineTooltip' }, //开启手机端tooltip
  106. ],
  107. Frame: //子框架设置
  108. [
  109. {SplitCount:3,Custom: [{ Type: 0, Position: 'right'}]},
  110. {SplitCount:2},
  111. {SplitCount:3},
  112. ],
  113. };
  114. return data;
  115. }
  116. DefaultData.GetMinuteOption=function()
  117. {
  118. var option=
  119. {
  120. Type:'分钟走势图', //创建图形类型
  121. Windows: //窗口指标
  122. [
  123. ],
  124. IsAutoUpdate:true, //是自动更新数据
  125. DayCount:1, //1 最新交易日数据 >1 多日走势图
  126. IsShowRightMenu:false, //是否显示右键菜单
  127. CorssCursorTouchEnd:true,
  128. IsClickShowCorssCursor:true,
  129. //IsFullDraw:true,
  130. CorssCursorInfo:{ Left:2, Right:2, Bottom:1 }, //十字光标刻度设置
  131. MinuteLine:
  132. {
  133. //IsDrawAreaPrice:false, //是否画价格面积图
  134. },
  135. Border: //边框
  136. {
  137. Left:1, //左边间距
  138. Right:1, //右边间距
  139. Top:20,
  140. Bottom:20
  141. },
  142. Frame: //子框架设置
  143. [
  144. {SplitCount:3},
  145. {SplitCount:2},
  146. {SplitCount:3},
  147. ],
  148. ExtendChart: //扩展图形
  149. [
  150. {Name:'MinuteTooltip' } //手机端tooltip
  151. ],
  152. };
  153. return option;
  154. }
  155. DefaultData.CreateGuid=function()
  156. {
  157. function S4()
  158. {
  159. return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
  160. }
  161. return "guid" + (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
  162. }
  163. var g_JSChart=new Map();
  164. export default
  165. {
  166. name:"HQChartControl",
  167. props:
  168. [
  169. 'DefaultSymbol',
  170. 'DefaultChart', //{ Type:, IsHScreen:}
  171. ],
  172. data()
  173. {
  174. let data=
  175. {
  176. Symbol:'600000.sh',
  177. ChartWidth:550,
  178. ChartHeight:1000,
  179. KLineID:"HQChart_"+DefaultData.CreateGuid(),
  180. KLine:
  181. {
  182. Option:DefaultData.GetKLineOption(),
  183. },
  184. Minute:
  185. {
  186. Option:DefaultData.GetMinuteOption(),
  187. },
  188. ChartType:"Minute",
  189. IsHScreen:false, //横屏
  190. CanvasNode:null,
  191. };
  192. return data;
  193. },
  194. created()
  195. {
  196. if (this.DefaultSymbol) this.Symbol=this.DefaultSymbol; //默认股票
  197. if (this.DefaultChart)
  198. {
  199. //TODO:默认天数,周期在这里加
  200. if (this.DefaultChart.Type=='Minute')
  201. {
  202. this.ChartType="Minute";
  203. }
  204. else
  205. {
  206. this.ChartType="KLine";
  207. }
  208. //横屏
  209. if (this.DefaultChart.IsHScreen) this.IsHScreen=this.DefaultChart.IsHScreen
  210. }
  211. },
  212. methods:
  213. {
  214. SetSize(width, height)
  215. {
  216. this.ChartWidth=width;
  217. this.ChartHeight=height;
  218. },
  219. GetJSChart()
  220. {
  221. if (g_JSChart.has(this.KLineID)) return g_JSChart.get(this.KLineID);
  222. return null;
  223. },
  224. SetJSChart(jsChart)
  225. {
  226. g_JSChart.set(this.KLineID,jsChart)
  227. },
  228. ClearChart()
  229. {
  230. console.log("[ClearChart] clear");
  231. var jsChart=this.GetJSChart();
  232. if (jsChart)
  233. {
  234. jsChart.ChartDestroy();
  235. this.SetJSChart(null);
  236. }
  237. // #ifdef H5
  238. var divKLine=document.getElementById(this.KLineID);
  239. while (divKLine.hasChildNodes())
  240. {
  241. divKLine.removeChild(divKLine.lastChild);
  242. } 
  243. // #endif
  244. },
  245. Draw(option)
  246. {
  247. console.log("[HQChartControl::Draw]");
  248. var jsChart=this.GetJSChart();
  249. if (!jsChart || !jsChart.JSChartContainer) return;
  250. jsChart.JSChartContainer.Draw();
  251. },
  252. OnSize(option)
  253. {
  254. // #ifdef H5
  255. this.OnSize_h5(option);
  256. // #endif
  257. // #ifndef H5
  258. this.OnSize_app(option);
  259. // #endif
  260. },
  261. OnSize_h5(option)
  262. {
  263. var chartHeight = this.ChartHeight;
  264. var chartWidth = this.ChartWidth;
  265. var kline=this.$refs.kline;
  266. kline.style.width=chartWidth+'px';
  267. kline.style.height=chartHeight+'px';
  268. var jsChart=this.GetJSChart();
  269. if (jsChart) jsChart.OnSize(option);
  270. },
  271. OnSize_app(option)
  272. {
  273. var jsChart=this.GetJSChart();
  274. if (jsChart)
  275. {
  276. jsChart.CanvasElement.Width=this.ChartWidth;
  277. jsChart.CanvasElement.Height=this.ChartHeight;
  278. jsChart.OnSize(option);
  279. }
  280. },
  281. SetHQChartStyle()
  282. {
  283. // #ifdef H5
  284. this.SetHQChartStyle_h5();
  285. // #endif
  286. // #ifndef H5
  287. this.SetHQChartStyle_app();
  288. // #endif
  289. },
  290. SetHQChartStyle_h5()
  291. {
  292. var blackStyle=HQChart.HQChartStyle.GetStyleConfig(HQChart.STYLE_TYPE_ID.BLACK_ID);
  293. HQChart.JSChart.SetStyle(blackStyle);
  294. this.$refs.kline.style.backgroundColor=blackStyle.BGColor; //div背景色设置黑色
  295. },
  296. SetHQChartStyle_app()
  297. {
  298. var blackStyle=JSCommonHQStyle.GetStyleConfig(JSCommonHQStyle.STYLE_TYPE_ID.BLACK_ID);
  299. JSCommon.JSChart.SetStyle(blackStyle);
  300. },
  301. CreateHQChart()
  302. {
  303. this.SetHQChartStyle();
  304. if (this.ChartType=="Minute")
  305. return this.CreateMinuteChart();
  306. else
  307. return this.CreateKLineChart();
  308. },
  309. CreateKLineChart_h5() //创建K线图
  310. {
  311. this.ClearChart();
  312. var chart=HQChart.JSChart.Init(this.$refs.kline);
  313. this.KLine.Option.Symbol=this.Symbol;
  314. this.KLine.Option.NetworkFilter=this.NetworkFilter;
  315. chart.SetOption(this.KLine.Option);
  316. this.SetJSChart(chart);
  317. return chart;
  318. },
  319. CreateKLineChart_app()
  320. {
  321. this.ClearChart();
  322. var element = new JSCommon.JSCanvasElement();
  323. // #ifdef APP-PLUS
  324. element.IsUniApp=true; //canvas需要指定下 是uniapp的app
  325. // #endif
  326. // #ifdef APP-HARMONY
  327. element.IsUniApp=true; //canvas需要指定下 是uniapp的app
  328. // #endif
  329. element.ID = this.KLineID;
  330. element.Height = this.ChartHeight; //高度宽度需要手动绑定!!
  331. element.Width = this.ChartWidth;
  332. var chart = JSCommon.JSChart.Init(element);
  333. this.KLine.Option.NetworkFilter=this.NetworkFilter;
  334. this.KLine.Option.Symbol=this.Symbol;
  335. //this.KLine.Option.IsClickShowCorssCursor=true;
  336. this.KLine.Option.IsFullDraw=true; //每次手势移动全屏重绘
  337. chart.SetOption(this.KLine.Option);
  338. this.SetJSChart(chart);
  339. return chart;
  340. },
  341. ChangeScriptIndex (windowIndex, indexData)
  342. {
  343. //{Name:指标名字, Script:指标脚本, Args:指标参数(数组) }
  344. //console.log(indexdata);
  345. var jsChart=this.GetJSChart();
  346. if (this.IsKLineChart() && jsChart) jsChart.ChangeScriptIndex(windowIndex,indexData);
  347. },
  348. CreateKLineChart_WeChat()
  349. {
  350. this.ClearChart();
  351. var id=`#${this.KLineID}`;
  352. wx.createSelectorQuery().in(this)
  353. .select(id)
  354. .fields({
  355. node: true,
  356. size: true,
  357. })
  358. .exec((res)=>
  359. {
  360. console.log("[HQChartControl::CreateKLineChart_WeChat] 2")
  361. this.CanvasNode= HQChartHelper.MarkRaw(res[0]);
  362. var element = new JSCommon.JSCanvasElement();
  363. element.ID = this.KLineID;
  364. element.CanvasNode =this.CanvasNode;
  365. element.Height = this.ChartHeight; //高度宽度需要手动绑定!!
  366. element.Width = this.ChartWidth;
  367. console.log("[HQChartControl::CreateKLineChart_WeChat] 3",this.ChartHeight,this.ChartWidth, res)
  368. var chart = JSCommon.JSChart.Init(element); //把画布绑定到行情模块中
  369. this.KLine.Option.NetworkFilter=this.NetworkFilter;
  370. this.KLine.Option.Symbol=this.Symbol;
  371. //this.KLine.Option.IsClickShowCorssCursor=true;
  372. this.KLine.Option.IsFullDraw=true; //每次手势移动全屏重绘
  373. chart.SetOption(this.KLine.Option);
  374. this.SetJSChart(chart);
  375. });
  376. },
  377. CreateKLineChart()
  378. {
  379. this.ChartType="KLine";
  380. if (this.IsHScreen) this.KLine.Option.Type="历史K线图横屏";
  381. else this.KLine.Option.Type="历史K线图";
  382. // #ifdef H5
  383. return this.CreateKLineChart_h5();
  384. // #endif
  385. // #ifdef MP-WEIXIN
  386. return this.CreateKLineChart_WeChat();
  387. // #endif
  388. // #ifndef H5 || MP-WEIXIN
  389. return this.CreateKLineChart_app();
  390. // #endif
  391. },
  392. CreateMinuteChart_h5() //创建日线图
  393. {
  394. this.ClearChart();
  395. var chart=HQChart.JSChart.Init(this.$refs.kline);
  396. this.Minute.Option.Symbol=this.Symbol;
  397. this.Minute.Option.NetworkFilter=this.NetworkFilter;
  398. chart.SetOption(this.Minute.Option);
  399. this.SetJSChart(chart);
  400. return chart;
  401. },
  402. CreateMinuteChart_app()
  403. {
  404. this.ClearChart();
  405. var element = new JSCommon.JSCanvasElement();
  406. // #ifdef APP-PLUS
  407. element.IsUniApp=true; //canvas需要指定下 是uniapp的app
  408. // #endif
  409. // #ifdef APP-HARMONY
  410. element.IsUniApp=true; //canvas需要指定下 是uniapp的app
  411. // #endif
  412. element.ID = this.KLineID;
  413. element.Height = this.ChartHeight; //高度宽度需要手动绑定!!
  414. element.Width = this.ChartWidth;
  415. var chart = JSCommon.JSChart.Init(element);
  416. this.Minute.Option.NetworkFilter=this.NetworkFilter;
  417. this.Minute.Option.Symbol=this.Symbol;
  418. this.Minute.Option.IsFullDraw=true; //每次手势移动全屏重绘
  419. chart.SetOption(this.Minute.Option);
  420. this.SetJSChart(chart);
  421. return chart;
  422. },
  423. CreateMinuteChart_WeChat()
  424. {
  425. this.ClearChart();
  426. var id=`#${this.KLineID}`;
  427. wx.createSelectorQuery().in(this)
  428. .select(id)
  429. .fields({
  430. node: true,
  431. size: true,
  432. })
  433. .exec((res)=>
  434. {
  435. this.CanvasNode= HQChartHelper.MarkRaw(res[0]);
  436. var element = new JSCommon.JSCanvasElement();
  437. element.ID = this.KLineID;
  438. element.CanvasNode =this.CanvasNode;
  439. element.Height = this.ChartHeight; //高度宽度需要手动绑定!!
  440. element.Width = this.ChartWidth;
  441. console.log("[HQChartControl::CreateMinuteChart_WeChat] 3",this.ChartHeight,this.ChartWidth, res)
  442. var chart = JSCommon.JSChart.Init(element); //把画布绑定到行情模块中
  443. this.Minute.Option.NetworkFilter=this.NetworkFilter;
  444. this.Minute.Option.Symbol=this.Symbol;
  445. this.Minute.Option.IsFullDraw=true; //每次手势移动全屏重绘
  446. chart.SetOption(this.Minute.Option);
  447. this.SetJSChart(chart);
  448. });
  449. },
  450. CreateMinuteChart()
  451. {
  452. this.ChartType="Minute";
  453. if (this.IsHScreen) this.Minute.Option.Type="分钟走势图横屏";
  454. else this.Minute.Option.Type="分钟走势图";
  455. // #ifdef H5
  456. return this.CreateMinuteChart_h5();
  457. // #endif
  458. // #ifdef MP-WEIXIN
  459. return this.CreateMinuteChart_WeChat();
  460. // #endif
  461. // #ifndef H5 || MP-WEIXIN
  462. return this.CreateMinuteChart_app();
  463. // #endif
  464. },
  465. IsKLineChart()
  466. {
  467. var jsChart=this.GetJSChart();
  468. if (!jsChart) return false;
  469. var className=jsChart.JSChartContainer.ClassName;
  470. if (className=="KLineChartContainer" || className=="KLineChartHScreenContainer") return true;
  471. return false;
  472. },
  473. IsMinuteChart()
  474. {
  475. var jsChart=this.GetJSChart();
  476. if (!jsChart) return false;
  477. var className=jsChart.JSChartContainer.ClassName;
  478. if (className=="MinuteChartContainer" || className=="MinuteChartHScreenContainer") return true;
  479. return false;
  480. },
  481. //K线周期切换
  482. ChangeKLinePeriod(period)
  483. {
  484. var jsChart=this.GetJSChart();
  485. this.KLine.Option.KLine.Period=period;
  486. if (this.IsKLineChart() && jsChart)
  487. {
  488. jsChart.ChangePeriod(period);
  489. }
  490. else
  491. {
  492. this.CreateKLineChart();
  493. }
  494. },
  495. //走势图多日切换
  496. ChangeMinutePeriod(dayCount)
  497. {
  498. var jsChart=this.GetJSChart();
  499. this.Minute.Option.DayCount=dayCount;
  500. if (this.IsMinuteChart() && jsChart)
  501. {
  502. jsChart.ChangeDayCount(dayCount);
  503. }
  504. else
  505. {
  506. this.CreateMinuteChart(); //类型不对 删了重建
  507. }
  508. },
  509. //切换指标 windowId=窗口索引 name=指标名字
  510. ChangeKLineIndex(windowId,name)
  511. {
  512. var jsChart=this.GetJSChart();
  513. if (this.IsKLineChart() && jsChart) jsChart.ChangeIndex(windowId,name);
  514. },
  515. //切换股票
  516. ChangeSymbol(symbol)
  517. {
  518. this.Symbol=symbol;
  519. var jsChart=this.GetJSChart();
  520. if (jsChart) jsChart.ChangeSymbol(symbol);
  521. },
  522. ChangeRight(right)
  523. {
  524. var jsChart=this.GetJSChart();
  525. if (this.IsKLineChart() && jsChart) jsChart.ChangeRight(right);
  526. },
  527. ChangeKLineDrawType(id)
  528. {
  529. var jsChart=this.GetJSChart();
  530. if (this.IsKLineChart() && jsChart) jsChart.ChangeKLineDrawType(id);
  531. },
  532. ///////////////////////////////////////////////
  533. //手势事件 app/小程序才有
  534. //KLine事件
  535. KLineTouchStart(event)
  536. {
  537. var jsChart=this.GetJSChart();
  538. if (jsChart)
  539. {
  540. var backup=this.ConvertTouchEventData(event);
  541. jsChart.OnTouchStart(event);
  542. this.RestoreTouchEventData(backup, event);
  543. }
  544. },
  545. KLineTouchMove (event)
  546. {
  547. var jsChart=this.GetJSChart();
  548. if (jsChart)
  549. {
  550. var backup=this.ConvertTouchEventData(event);
  551. jsChart.OnTouchMove(event);
  552. this.RestoreTouchEventData(backup, event);
  553. }
  554. },
  555. KLineTouchEnd (event)
  556. {
  557. var jsChart=this.GetJSChart();
  558. if (jsChart)
  559. {
  560. var backup=this.ConvertTouchEventData(event);
  561. jsChart.OnTouchEnd(event);
  562. this.RestoreTouchEventData(backup, event);
  563. }
  564. },
  565. ConvertTouchEventData(event)
  566. {
  567. if (Array.isArray(event.touches)) return null;
  568. var touches=event.touches; //备份下
  569. var aryTouches=[];
  570. for(var i=0;i<10;++i)
  571. {
  572. var key=i.toString();
  573. var item=event.touches[key];
  574. if (!item) break;
  575. aryTouches[i]=item;
  576. }
  577. event.touches=aryTouches;
  578. var changedTouches=event.changedTouches;
  579. var aryChangedTouches=[];
  580. for(var i=0;i<10;++i)
  581. {
  582. var key=i.toString();
  583. var item=event.changedTouches[key];
  584. if (!item) break;
  585. aryChangedTouches[i]=item;
  586. }
  587. event.changedTouches=aryChangedTouches;
  588. //console.log('ConvertTouchEventData' ,event )
  589. return {Touches:touches, ChangedTouches:changedTouches };
  590. },
  591. RestoreTouchEventData(backup, event)
  592. {
  593. if (!backup) return;
  594. event.touches=backup.Touches; //还原原来的touches结构
  595. event.changedTouches=backup.ChangedTouches
  596. //console.log('RestoreTouchEventData' ,event )
  597. },
  598. /////////////////////////////////////////////////////////////////////////////////////////
  599. NetworkFilter(data, callback)
  600. {
  601. console.log(`[HQChartTemplate:NetworkFilter] Name=${data.Name} Explain=${data.Explain}` );
  602. },
  603. },
  604. }
  605. </script>
  606. <style>
  607. </style>