You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2137 lines
81 KiB

  1. /*
  2. copyright (c) 2018 jones
  3. http://www.apache.org/licenses/LICENSE-2.0
  4. 开源项目 https://github.com/jones2000/HQChart
  5. jones_2000@163.com
  6. 标题画法
  7. */
  8. import
  9. {
  10. g_JSChartResource,
  11. JSCHART_LANGUAGE_ID,
  12. g_JSChartLocalization,
  13. } from './umychart.resource.wechat.js'
  14. import
  15. {
  16. ChartData, HistoryData,
  17. SingleData, MinuteData,
  18. CUSTOM_DAY_PERIOD_START,
  19. CUSTOM_DAY_PERIOD_END,
  20. CUSTOM_MINUTE_PERIOD_START,
  21. CUSTOM_MINUTE_PERIOD_END,
  22. CUSTOM_SECOND_PERIOD_START,
  23. CUSTOM_SECOND_PERIOD_END,
  24. JSCHART_EVENT_ID,
  25. CloneData
  26. } from "./umychart.data.wechat.js";
  27. import
  28. {
  29. JSCommonCoordinateData
  30. } from "./umychart.coordinatedata.wechat.js";
  31. import
  32. {
  33. KLINE_INFO_TYPE,
  34. } from "./umychart.klineinfo.wechat.js";
  35. import
  36. {
  37. IFrameSplitOperator,
  38. } from './umychart.framesplit.wechat.js'
  39. var MARKET_SUFFIX_NAME = JSCommonCoordinateData.MARKET_SUFFIX_NAME;
  40. function ToFixedPoint(value)
  41. {
  42. //return value;
  43. return parseInt(value) + 0.5;
  44. }
  45. function ToFixedRect(value)
  46. {
  47. var rounded;
  48. return rounded = (0.5 + value) << 0;
  49. }
  50. //标题画法基类
  51. function IChartTitlePainting()
  52. {
  53. this.Frame;
  54. this.Data = new Array();
  55. this.Canvas; //画布
  56. this.IsDynamic = false; //是否是动态标题
  57. this.Position = 0; //标题显示位置 0 框架里的标题 1 框架上面
  58. this.CursorIndex; //数据索引
  59. this.Font = g_JSChartResource.DynamicTitleFont;//"12px 微软雅黑";
  60. this.Title; //固定标题(可以为空)
  61. this.TitleColor = g_JSChartResource.DefaultTextColor;
  62. this.LanguageID = JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID;
  63. this.UpdateUICallback; //通知外面更新标题(老接口废弃)
  64. this.OnDrawEvent; //外部事件通知
  65. this.GetEventCallback; //事件回调,新的版本同意都用这个
  66. }
  67. var PERIOD_NAME = ["日线", "周线", "月线", "年线", "1分", "5分", "15分", "30分", "60分", "季线", "分笔", "2小时", "4小时", "", ""];
  68. var RIGHT_NAME = ['不复权', '前复权', '后复权'];
  69. //K线标题
  70. function DynamicKLineTitlePainting()
  71. {
  72. this.newMethod = IChartTitlePainting; //派生
  73. this.newMethod();
  74. delete this.newMethod;
  75. this.ClassName ='DynamicKLineTitlePainting';
  76. this.IsDynamic = true;
  77. this.IsShow = true; //是否显示
  78. this.LineCount = 1; //默认显示1行
  79. this.SpaceWidth = 1; //空格宽度
  80. this.TextSpace=-1; //文字之间的间距
  81. this.DateTimeSpace=2; //日期时间向后间距
  82. this.PeriodSpace=1; //周期向后间距
  83. this.NameSpace=1; //名字向后间距
  84. this.Period; //周期
  85. this.UpColor = g_JSChartResource.UpTextColor;
  86. this.DownColor = g_JSChartResource.DownTextColor;
  87. this.UnchagneColor = g_JSChartResource.UnchagneTextColor;
  88. this.VolColor=g_JSChartResource.Title.VolColor;
  89. this.AmountColor=g_JSChartResource.Title.AmountColor;
  90. this.DateTimeColor=g_JSChartResource.Title.DateTimeColor;
  91. this.NameColor = g_JSChartResource.Title.NameColor;
  92. this.SettingColor=g_JSChartResource.Title.SettingColor; //周期 复权
  93. this.PositionColor=g_JSChartResource.Title.PositionColor; //持仓
  94. this.Symbol;
  95. this.UpperSymbol;
  96. this.Name;
  97. this.InfoData;
  98. this.InfoTextHeight = 15;
  99. this.InfoTextColor = g_JSChartResource.KLine.Info.TextColor;
  100. this.InfoTextBGColor = g_JSChartResource.KLine.Info.TextBGColor;
  101. this.IsShowName = true; //是否显示股票名称
  102. this.IsShowSettingInfo = true; //是否显示设置信息(周期 复权)
  103. this.HQChart;
  104. this.GetCurrentKLineData = function () //获取当天鼠标位置所在的K线数据
  105. {
  106. if (this.CursorIndex == null || !this.Data) return null;
  107. if (this.Data.length <= 0) return null;
  108. var index = this.CursorIndex;
  109. index = parseInt(index.toFixed(0));
  110. var dataIndex = this.Data.DataOffset + index;
  111. if (dataIndex >= this.Data.Data.length) dataIndex = this.Data.Data.length - 1;
  112. if (dataIndex < 0) return null;
  113. var item = this.Data.Data[dataIndex];
  114. return item;
  115. }
  116. this.GetDataIndex=function()
  117. {
  118. if (this.CursorIndex == null || !this.Data) return null;
  119. if (this.Data.length <= 0) return null;
  120. var index = this.CursorIndex;
  121. index = parseInt(index.toFixed(0));
  122. var dataIndex = this.Data.DataOffset + index;
  123. if (dataIndex >= this.Data.Data.length) dataIndex = this.Data.Data.length - 1;
  124. if (dataIndex < 0) return null;
  125. return dataIndex;
  126. }
  127. this.SendUpdateUIMessage = function (funcName) //通知外面 标题变了
  128. {
  129. if (!this.UpdateUICallback) return;
  130. var sendData = {
  131. TitleName: 'K线标题', CallFunction: funcName, Stock: { Name: this.Name, Symbol: this.Symbol, },
  132. Rect:
  133. {
  134. Left: this.Frame.ChartBorder.GetLeft(), Right: this.Frame.ChartBorder.GetRight(),
  135. Top: 0, Bottom: this.Frame.ChartBorder.GetTop(),
  136. }
  137. };
  138. //有数据
  139. if (this.Data && this.Data.Data && this.Data.Data.length > 0) {
  140. let index = this.Data.Data.length - 1; //默认最后一天的数据
  141. if (this.CursorIndex) {
  142. let cursorIndex = Math.abs(this.CursorIndex - 0.5);
  143. cursorIndex = parseInt(cursorIndex.toFixed(0));
  144. index = this.Data.DataOffset + cursorIndex;
  145. if (index >= this.Data.Data.length) index = this.Data.Data.length - 1;
  146. }
  147. if (index >= 0) {
  148. let item = this.Data.Data[index];
  149. sendData.Stock.Data =
  150. {
  151. Date: item.Date,
  152. YClose: item.YClose, Open: item.Open, High: item.High, Low: item.Low, Close: item.Close,
  153. Vol: item.Vol, Amount: item.Amount
  154. }
  155. if (item.Time) sendData.Stock.Time = item.Time; //分钟K线才有时间
  156. }
  157. if (this.Data.Period != null) sendData.Stock.PeriodName = this.GetPeriodName(this.Data.Period); //周期名字
  158. if (this.Data.Right != null) sendData.Stock.RightName = RIGHT_NAME[this.Data.Right]; //复权名字
  159. }
  160. //console.log('[DynamicKLineTitlePainting::SendUpdateUIMessage', sendData);
  161. this.UpdateUICallback(sendData);
  162. }
  163. this.GetPeriodName = function (period)
  164. {
  165. var name = '';
  166. if (period > CUSTOM_MINUTE_PERIOD_START && period <= CUSTOM_MINUTE_PERIOD_END)
  167. name = (period - CUSTOM_MINUTE_PERIOD_START) + g_JSChartLocalization.GetText('自定义分钟', this.LanguageID);
  168. else if (period > CUSTOM_DAY_PERIOD_START && period <= CUSTOM_DAY_PERIOD_END)
  169. name = (period - CUSTOM_DAY_PERIOD_START) + g_JSChartLocalization.GetText('自定义日线',this.LanguageID);
  170. else if (period > CUSTOM_SECOND_PERIOD_START && period <= CUSTOM_SECOND_PERIOD_END)
  171. name = (period - CUSTOM_SECOND_PERIOD_START) + g_JSChartLocalization.GetText('自定义秒', this.LanguageID);
  172. else
  173. name = g_JSChartLocalization.GetText(ChartData.GetPeriodName(period), this.LanguageID);
  174. return name;
  175. }
  176. this.GetRightName = function (rightID, periodID)
  177. {
  178. if (!MARKET_SUFFIX_NAME.IsEnableRight(periodID, this.Symbol, this.HQChart.RightFormula)) return null;
  179. var rightName = RIGHT_NAME[rightID];
  180. return rightName
  181. }
  182. this.FullDraw=function()
  183. {
  184. if (!this.IsShow) return;
  185. this.UpperSymbol=this.Symbol ? this.Symbol.toUpperCase():'';
  186. if (this.CursorIndex == null || !this.Data || this.Data.length <= 0)
  187. {
  188. this.OnDrawEventCallback(null, 'DynamicKLineTitlePainting::FullDraw');
  189. return;
  190. }
  191. if (this.TextSpace>=0)
  192. {
  193. this.SpaceWidth=this.TextSpace;
  194. }
  195. else
  196. {
  197. this.Canvas.font = this.Font;
  198. this.SpaceWidth = this.Canvas.measureText(' ').width;
  199. }
  200. var index = this.CursorIndex;
  201. index = parseInt(index.toFixed(0));
  202. var dataIndex = this.Data.DataOffset + index;
  203. if (dataIndex >= this.Data.Data.length) dataIndex=-1;
  204. if (dataIndex < 0)
  205. {
  206. this.OnDrawEventCallback(null, 'DynamicKLineTitlePainting::FullDraw');
  207. return;
  208. }
  209. var item = this.Data.Data[dataIndex];
  210. this.OnDrawEventCallback(item, 'DynamicKLineTitlePainting::FullDraw');
  211. //console.log('[FullDraw]', item);
  212. if (this.Frame.IsHScreen === true)
  213. {
  214. this.Canvas.save();
  215. if (this.LineCount > 1) this.DrawMulitLine(item);
  216. else this.DrawSingleLine(item,true);
  217. this.Canvas.restore();
  218. if (!item.Time && item.Date && this.InfoData) this.HSCreenKLineInfoDraw(item.Date);
  219. }
  220. else
  221. {
  222. if (this.LineCount > 1) this.DrawMulitLine(item);
  223. else this.DrawSingleLine(item, true);
  224. if (!item.Time && item.Date && this.InfoData) this.KLineInfoDraw(item.Date);
  225. }
  226. }
  227. this.DrawTitle = function ()
  228. {
  229. this.UpperSymbol=this.Symbol ? this.Symbol.toUpperCase():'';
  230. this.SendUpdateUIMessage('DrawTitle');
  231. this.OnDrawEventCallback(null, 'DynamicKLineTitlePainting::DrawTitle');
  232. if (!this.IsShow) return;
  233. if (!this.IsShowName && !this.IsShowSettingInfo) return;
  234. if (this.LineCount > 1) return;
  235. if (this.Frame.IsHScreen === true)
  236. {
  237. this.Canvas.save();
  238. this.HScreenDrawTitle();
  239. this.Canvas.restore();
  240. return;
  241. }
  242. var left = this.Frame.ChartBorder.GetLeft();
  243. var bottom = this.Frame.ChartBorder.GetTop();
  244. var right = this.Frame.ChartBorder.GetRight();
  245. if (bottom < 5) return;
  246. this.Canvas.textAlign = "left";
  247. this.Canvas.textBaseline = "bottom";
  248. this.Canvas.font = this.Font;
  249. var position = { Left: left, Bottom: bottom, IsHScreen: false };
  250. if (this.IsShowName && this.Name)
  251. {
  252. if (!this.DrawKLineText(this.Name, this.NameColor, position)) return;
  253. }
  254. if (this.IsShowSettingInfo && this.Data.Period != null && this.Data.Right != null)
  255. {
  256. var periodName = this.GetPeriodName(this.Data.Period);
  257. var rightName = this.GetRightName(this.Data.Right,this.Data.Period);
  258. var text = "(" + periodName + ")";
  259. if (rightName) text = "(" + periodName + " " + rightName + ")";
  260. if (!this.DrawKLineText(text, this.SettingColor, position)) return;
  261. }
  262. }
  263. this.HScreenDrawTitle = function ()
  264. {
  265. var xText = this.Frame.ChartBorder.GetRight();
  266. var yText = this.Frame.ChartBorder.GetTop();
  267. var right = this.Frame.ChartBorder.GetHeight();
  268. if (this.Frame.ChartBorder.Right < 10) return;
  269. this.Canvas.translate(xText, yText);
  270. this.Canvas.rotate(90 * Math.PI / 180);
  271. this.Canvas.textAlign = "left";
  272. this.Canvas.textBaseline = "bottom";
  273. this.Canvas.font = this.Font;
  274. var left = 2;
  275. var bottom = -2;
  276. var position = { Left: left, Bottom: bottom, IsHScreen: false };
  277. if (this.IsShowName && this.Name)
  278. {
  279. if (!this.DrawKLineText(this.Name, this.NameColor, position)) return;
  280. }
  281. if (this.IsShowSettingInfo && this.Data.Period != null && this.Data.Right != null)
  282. {
  283. var periodName = this.GetPeriodName(this.Data.Period);
  284. var rightName = this.GetRightName(this.Data.Right,this.Data.Period);
  285. var text = "(" + periodName + ")";
  286. if (rightName) text = "(" + periodName + " " + rightName + ")";
  287. if (!this.DrawKLineText(text, this.SettingColor, position)) return;
  288. }
  289. }
  290. this.DrawMulitLine = function (item) //画多行
  291. {
  292. var isHScreen = this.Frame.IsHScreen === true;
  293. var leftSpace = 1;
  294. var bottomSpace = 1;
  295. var left = this.Frame.ChartBorder.GetLeft() + leftSpace;;
  296. var width = this.Frame.ChartBorder.GetWidth();
  297. var height = this.Frame.ChartBorder.GetTop();
  298. var defaultfloatPrecision = JSCommonCoordinateData.GetfloatPrecision(this.Symbol);//价格小数位数
  299. if (isHScreen)
  300. {
  301. var left = leftSpace;;
  302. var width = this.Frame.ChartBorder.GetHeight();
  303. var height = this.Frame.ChartBorder.Right;
  304. var xText = this.Frame.ChartBorder.GetChartWidth();
  305. var yText = this.Frame.ChartBorder.GetTop();
  306. this.Canvas.translate(xText, yText);
  307. this.Canvas.rotate(90 * Math.PI / 180);
  308. }
  309. var itemHeight = (height - bottomSpace) / this.LineCount;
  310. var itemWidth = (width - leftSpace) / 4;
  311. var bottom = itemHeight;
  312. this.Canvas.textAlign = "left";
  313. this.Canvas.textBaseline = "bottom";
  314. this.Canvas.font = this.Font;
  315. var text = IFrameSplitOperator.FormatDateString(item.Date);
  316. this.Canvas.fillStyle = this.DateTimeColor;
  317. this.Canvas.fillText(text, left, bottom, itemWidth);
  318. left += itemWidth;
  319. this.Canvas.textAlign = "left";
  320. this.Canvas.fillStyle = this.GetColor(item.Open, item.YClose);
  321. var text = g_JSChartLocalization.GetText('Tooltip-Open', this.LanguageID) + item.Open.toFixed(defaultfloatPrecision);
  322. this.Canvas.fillText(text, left, bottom, itemWidth);
  323. left += itemWidth;
  324. this.Canvas.fillStyle = this.GetColor(item.High, item.YClose);
  325. var text = g_JSChartLocalization.GetText('Tooltip-High', this.LanguageID) + item.High.toFixed(defaultfloatPrecision);
  326. this.Canvas.fillText(text, left, bottom, itemWidth);
  327. left += itemWidth;
  328. var value = (item.Close - item.YClose) / item.YClose * 100;
  329. this.Canvas.fillStyle = this.GetColor(value, 0);
  330. var text = g_JSChartLocalization.GetText('Tooltip-Increase', this.LanguageID) + value.toFixed(2) + '%';
  331. this.Canvas.fillText(text, left, bottom, itemWidth);
  332. left += itemWidth;
  333. bottom += itemHeight; //换行
  334. var left = this.Frame.ChartBorder.GetLeft() + leftSpace;
  335. if (isHScreen) left = leftSpace;
  336. if (ChartData.IsMinutePeriod(this.Period, true) && item.Time)
  337. {
  338. this.Canvas.fillStyle = this.DateTimeColor;
  339. var text = IFrameSplitOperator.FormatTimeString(item.Time);
  340. this.Canvas.fillText(text, left, bottom, itemWidth);
  341. }
  342. else if (ChartData.IsSecondPeriod(this.Period) && item.Time)
  343. {
  344. this.Canvas.fillStyle = this.SettingColor;
  345. var text = IFrameSplitOperator.FormatTimeString(item.Time, 'HH:MM:SS');
  346. this.Canvas.fillText(text, left, bottom, itemWidth);
  347. }
  348. left += itemWidth;
  349. this.Canvas.fillStyle = this.GetColor(item.Close, item.YClose);
  350. var text = g_JSChartLocalization.GetText('Tooltip-Close', this.LanguageID) + item.Close.toFixed(defaultfloatPrecision);
  351. this.Canvas.fillText(text, left, bottom, itemWidth);
  352. left += itemWidth;
  353. this.Canvas.fillStyle = this.GetColor(item.Low, item.YClose);
  354. var text = g_JSChartLocalization.GetText('Tooltip-Low', this.LanguageID) + item.Low.toFixed(defaultfloatPrecision);
  355. this.Canvas.fillText(text, left, bottom, itemWidth);
  356. left += itemWidth;
  357. this.Canvas.fillStyle = this.AmountColor;
  358. var text = g_JSChartLocalization.GetText('Tooltip-Amount', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Amount, 2, this.LanguageID);
  359. this.Canvas.fillText(text, left, bottom, itemWidth);
  360. left += itemWidth;
  361. }
  362. this.GetFormatTitle=function(data)
  363. {
  364. if (!data || !data.Data) return null;
  365. var aryText=[];
  366. var item=data.Data;
  367. var defaultfloatPrecision = JSCommonCoordinateData.GetfloatPrecision(this.Symbol);//价格小数位数
  368. if (this.IsShowName) //名称
  369. aryText.push({Text:this.Name, Color:this.NameColor, LeftSpace:this.NameSpace});
  370. if (this.IsShowSettingInfo) //周期 复权信息
  371. {
  372. var periodName = this.GetPeriodName(this.Data.Period);
  373. var rightName = this.GetRightName(this.Data.Right,this.Data.Period);
  374. var text = "(" + periodName + ")";
  375. if (rightName) text = "(" + periodName + " " + rightName + ")";
  376. aryText.push({Text:text, Color:this.SettingColor, LeftSpace:this.PeriodSpace});
  377. }
  378. var text = IFrameSplitOperator.FormatDateString(item.Date); //日期
  379. if (ChartData.IsDayPeriod(this.Period, true))
  380. {
  381. aryText.push({Text:text, Color:this.DateTimeColor, LeftSpace:this.DateTimeSpace});
  382. }
  383. else if (ChartData.IsMinutePeriod(this.Period, true))
  384. {
  385. if (IFrameSplitOperator.IsNumber(item.Time))
  386. {
  387. var timeText = IFrameSplitOperator.FormatTimeString(item.Time,"HH:MM");
  388. text=`${text} ${timeText}`;
  389. }
  390. aryText.push({Text:text, Color:this.DateTimeColor, LeftSpace:this.DateTimeSpace});
  391. }
  392. else if (ChartData.IsSecondPeriod(this.Period) )
  393. {
  394. if (IFrameSplitOperator.IsNumber(item.Time))
  395. {
  396. var timeText = IFrameSplitOperator.FormatTimeString(item.Time, "HH:MM:SS");
  397. text=`${text} ${timeText}`;
  398. }
  399. aryText.push({Text:text, Color:this.DateTimeColor, LeftSpace:this.DateTimeSpace});
  400. }
  401. //开
  402. if (IFrameSplitOperator.IsNumber(item.Open))
  403. {
  404. var color = this.GetColor(item.Open, item.YClose);
  405. var text = g_JSChartLocalization.GetText('KTitle-Open', this.LanguageID) + item.Open.toFixed(defaultfloatPrecision);
  406. aryText.push({Text:text, Color:color});
  407. }
  408. //高
  409. if (IFrameSplitOperator.IsNumber(item.High))
  410. {
  411. var color = this.GetColor(item.High, item.YClose);
  412. var text = g_JSChartLocalization.GetText('KTitle-High', this.LanguageID) + item.High.toFixed(defaultfloatPrecision);
  413. aryText.push({Text:text, Color:color});
  414. }
  415. //低
  416. if (IFrameSplitOperator.IsNumber(item.Low))
  417. {
  418. var color = this.GetColor(item.Low, item.YClose);
  419. var text = g_JSChartLocalization.GetText('KTitle-Low', this.LanguageID) + item.Low.toFixed(defaultfloatPrecision);
  420. aryText.push({Text:text, Color:color});
  421. }
  422. //收
  423. if (IFrameSplitOperator.IsNumber(item.Close))
  424. {
  425. var color = this.GetColor(item.Close, item.YClose);
  426. var text = g_JSChartLocalization.GetText('KTitle-Close', this.LanguageID) + item.Close.toFixed(defaultfloatPrecision);
  427. aryText.push({Text:text, Color:color});
  428. }
  429. if (IFrameSplitOperator.IsNumber(item.Vol))
  430. {
  431. var text = g_JSChartLocalization.GetText('KTitle-Vol', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Vol, 2, this.LanguageID);
  432. aryText.push({Text:text, Color:this.VolColor});
  433. }
  434. if (IFrameSplitOperator.IsNumber(item.Amount))
  435. {
  436. var text = g_JSChartLocalization.GetText('KTitle-Amount', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Amount, 2, this.LanguageID);
  437. aryText.push({Text:text, Color:this.AmountColor});
  438. }
  439. if (MARKET_SUFFIX_NAME.IsChinaFutures(this.UpperSymbol) && IFrameSplitOperator.IsNumber(item.Position))
  440. {
  441. var text = g_JSChartLocalization.GetText('KTitle-Position', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Position, 2, this.LanguageID);
  442. aryText.push({Text:text, Color:this.PositionColor});
  443. }
  444. return { AryText:aryText };
  445. }
  446. this.DrawSingleLine = function (item,bDrawTitle) //画单行
  447. {
  448. var isHScreen = this.Frame.IsHScreen === true;
  449. var left = this.Frame.ChartBorder.GetLeft();
  450. //var bottom=this.Frame.ChartBorder.GetTop()-this.Frame.ChartBorder.Top/2;
  451. var bottom = this.Frame.ChartBorder.GetTop();
  452. var right = this.Frame.ChartBorder.GetRight();
  453. var defaultfloatPrecision = JSCommonCoordinateData.GetfloatPrecision(this.Symbol);//价格小数位数
  454. if (isHScreen)
  455. {
  456. right = this.Frame.ChartBorder.GetHeight();
  457. if (this.Frame.ChartBorder.Right < 5) return;
  458. left = 2;
  459. bottom = -2;
  460. var xText = this.Frame.ChartBorder.GetRight();
  461. var yText = this.Frame.ChartBorder.GetTop();
  462. this.Canvas.translate(xText, yText);
  463. this.Canvas.rotate(90 * Math.PI / 180);
  464. }
  465. else
  466. {
  467. if (bottom < 5) return;
  468. }
  469. this.Canvas.textAlign = "left";
  470. this.Canvas.textBaseline = "bottom";
  471. this.Canvas.font = this.Font;
  472. var position = { Left: left, Bottom: bottom, IsHScreen: isHScreen };
  473. var titleData=this.GetFormatTitle({ Data:item });
  474. if (titleData && IFrameSplitOperator.IsNonEmptyArray(titleData.AryText))
  475. {
  476. for(var i=0;i<titleData.AryText.length;++i)
  477. {
  478. var item=titleData.AryText[i];
  479. if (!this.DrawKLineText(item.Text, item.Color, position, bDrawTitle==true)) break;
  480. if (IFrameSplitOperator.IsNumber(item.LeftSpace)) position.Left+=item.LeftSpace;
  481. }
  482. }
  483. /*
  484. if (this.IsShowName) //名称
  485. {
  486. if (!this.DrawKLineText(this.Name, this.NameColor, position, bDrawTitle==true)) return;
  487. position.Left+=this.NameSpace;
  488. }
  489. if (this.IsShowSettingInfo) //周期 复权信息
  490. {
  491. var periodName = this.GetPeriodName(this.Data.Period);
  492. var rightName = this.GetRightName(this.Data.Right,this.Data.Period);
  493. var text = "(" + periodName + ")";
  494. if (rightName) text = "(" + periodName + " " + rightName + ")";
  495. if (!this.DrawKLineText(text, this.SettingColor, position, bDrawTitle==true)) return;
  496. position.Left+=this.PeriodSpace;
  497. }
  498. var text = IFrameSplitOperator.FormatDateString(item.Date); //日期
  499. if (ChartData.IsDayPeriod(this.Period, true))
  500. {
  501. if (!this.DrawKLineText(text, this.DateTimeColor, position)) return;
  502. position.Left+=this.DateTimeSpace;
  503. }
  504. else if (ChartData.IsMinutePeriod(this.Period, true))
  505. {
  506. if (IFrameSplitOperator.IsNumber(item.Time))
  507. {
  508. var timeText = IFrameSplitOperator.FormatTimeString(item.Time,"HH:MM");
  509. text=`${text} ${timeText}`;
  510. }
  511. if (!this.DrawKLineText(text, this.DateTimeColor, position)) return;
  512. position.Left+=this.DateTimeSpace;
  513. }
  514. else if (ChartData.IsSecondPeriod(this.Period) )
  515. {
  516. if (IFrameSplitOperator.IsNumber(item.Time))
  517. {
  518. var timeText = IFrameSplitOperator.FormatTimeString(item.Time, "HH:MM:SS");
  519. text=`${text} ${timeText}`;
  520. }
  521. if (!this.DrawKLineText(text, this.DateTimeColor, position)) return;
  522. position.Left+=this.DateTimeSpace;
  523. }
  524. var color = this.GetColor(item.Open, item.YClose);
  525. var text = g_JSChartLocalization.GetText('KTitle-Open', this.LanguageID) + item.Open.toFixed(defaultfloatPrecision);
  526. if (!this.DrawKLineText(text, color, position)) return;
  527. var color = this.GetColor(item.High, item.YClose);
  528. var text = g_JSChartLocalization.GetText('KTitle-High', this.LanguageID) + item.High.toFixed(defaultfloatPrecision);
  529. if (!this.DrawKLineText(text, color, position)) return;
  530. var color = this.GetColor(item.Low, item.YClose);
  531. var text = g_JSChartLocalization.GetText('KTitle-Low', this.LanguageID) + item.Low.toFixed(defaultfloatPrecision);
  532. if (!this.DrawKLineText(text, color, position)) return;
  533. var color = this.GetColor(item.Close, item.YClose);
  534. var text = g_JSChartLocalization.GetText('KTitle-Close', this.LanguageID) + item.Close.toFixed(defaultfloatPrecision);
  535. if (!this.DrawKLineText(text, color, position)) return;
  536. if (IFrameSplitOperator.IsNumber(item.Vol))
  537. {
  538. var text = g_JSChartLocalization.GetText('KTitle-Vol', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Vol, 2, this.LanguageID);
  539. if (!this.DrawKLineText(text, this.VolColor, position)) return;
  540. }
  541. if (IFrameSplitOperator.IsNumber(item.Amount))
  542. {
  543. var text = g_JSChartLocalization.GetText('KTitle-Amount', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Amount, 2, this.LanguageID);
  544. if (!this.DrawKLineText(text, this.AmountColor, position)) return;
  545. }
  546. if (MARKET_SUFFIX_NAME.IsChinaFutures(this.UpperSymbol) && IFrameSplitOperator.IsNumber(item.Position))
  547. {
  548. var text = g_JSChartLocalization.GetText('KTitle-Position', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Position, 2, this.LanguageID);
  549. if (!this.DrawKLineText(text, this.PositionColor, position)) return;
  550. }
  551. */
  552. }
  553. this.OnDrawEventCallback = function (drawData, explain)
  554. {
  555. if (!this.OnDrawEvent || !this.OnDrawEvent.Callback) return;
  556. var data = { Draw: drawData, Name: this.ClassName, Explain: explain };
  557. if (this.Data && this.Data.Data)
  558. {
  559. if (IFrameSplitOperator.IsNumber(this.CursorIndex))
  560. {
  561. var index = this.CursorIndex;
  562. index = parseInt(index.toFixed(0));
  563. var dataIndex = this.Data.DataOffset + index;
  564. }
  565. else
  566. {
  567. dataIndex=this.Data.Data.length-1;
  568. }
  569. var dataCount=this.Data.Data.length;
  570. data.DataIndex=dataIndex;
  571. data.DataCount=dataCount;
  572. }
  573. this.OnDrawEvent.Callback(this.OnDrawEvent, data, this);
  574. }
  575. this.Draw = function ()
  576. {
  577. this.UpperSymbol = this.Symbol ? this.Symbol.toUpperCase() : '';
  578. this.SendUpdateUIMessage('Draw');
  579. if (!this.IsShow) return;
  580. if (this.CursorIndex == null || !this.Data || this.Data.length <= 0)
  581. {
  582. this.OnDrawEventCallback(null, 'DynamicKLineTitlePainting::Draw');
  583. return;
  584. }
  585. this.SpaceWidth = this.Canvas.measureText(' ').width;
  586. var index = this.CursorIndex;
  587. index = parseInt(index.toFixed(0));
  588. var dataIndex = this.Data.DataOffset + index;
  589. if (dataIndex >= this.Data.Data.length) dataIndex = this.Data.Data.length - 1;
  590. if (dataIndex < 0)
  591. {
  592. this.OnDrawEventCallback(null, 'DynamicKLineTitlePainting::Draw');
  593. return;
  594. }
  595. var item = this.Data.Data[dataIndex];
  596. this.OnDrawEventCallback(item, 'DynamicKLineTitlePainting::Draw');
  597. if (this.Frame.IsHScreen === true)
  598. {
  599. this.Canvas.save();
  600. if (this.LineCount > 1) this.DrawMulitLine(item);
  601. else this.DrawSingleLine(item);
  602. this.Canvas.restore();
  603. if (!item.Time && item.Date && this.InfoData) this.HSCreenKLineInfoDraw(item.Date);
  604. }
  605. else
  606. {
  607. if (this.LineCount > 1) this.DrawMulitLine(item);
  608. else this.DrawSingleLine(item);
  609. if (!item.Time && item.Date && this.InfoData) this.KLineInfoDraw(item.Date);
  610. }
  611. }
  612. this.KLineInfoDraw = function (date) {
  613. var info = this.InfoData.get(date.toString());
  614. if (!info) return;
  615. var invesotrCount = 0; //互动易统计
  616. var researchCouunt = 0;
  617. var reportCount = 0;
  618. var blockTradeCount = 0; //大宗交易次数
  619. var tradeDetailCount = 0; //龙虎榜上榜次数
  620. var policyData = null;
  621. var reportTitle = null, pforecastTitle = null;
  622. //console.log(info);
  623. for (var i in info.Data) {
  624. var item = info.Data[i];
  625. switch (item.InfoType) {
  626. case KLINE_INFO_TYPE.INVESTOR:
  627. ++invesotrCount;
  628. break;
  629. case KLINE_INFO_TYPE.PFORECAST:
  630. pforecastTitle = item.Title;
  631. break;
  632. case KLINE_INFO_TYPE.ANNOUNCEMENT:
  633. ++reportCount;
  634. break;
  635. case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_1:
  636. case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_2:
  637. case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_3:
  638. case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_4:
  639. reportTitle = item.Title;
  640. break;
  641. case KLINE_INFO_TYPE.RESEARCH:
  642. ++researchCouunt;
  643. break;
  644. case KLINE_INFO_TYPE.BLOCKTRADING:
  645. ++blockTradeCount;
  646. break;
  647. case KLINE_INFO_TYPE.TRADEDETAIL:
  648. ++tradeDetailCount;
  649. break;
  650. case KLINE_INFO_TYPE.POLICY:
  651. policyData = item;
  652. break;
  653. }
  654. }
  655. var isHScreen = (this.Frame.IsHScreen === true);
  656. var right = this.Frame.ChartBorder.GetRight() - 4;
  657. var top = this.Frame.ChartBorder.GetTopEx();
  658. if (isHScreen) {
  659. right = this.Frame.ChartBorder.GetBottom() - 4;
  660. top = this.Frame.ChartBorder.GetRightEx();
  661. this.Canvas.translate(top, right);
  662. this.Canvas.rotate(90 * Math.PI / 180);
  663. right = 0; top = 0;
  664. }
  665. this.Canvas.font = this.Font;
  666. var aryTitle = [];
  667. var position = { Top: top, Right: right, IsHScreen: isHScreen };
  668. aryTitle.push(IFrameSplitOperator.FormatDateString(date));
  669. if (reportTitle) aryTitle.push(reportTitle); //季报
  670. if (pforecastTitle) aryTitle.push(pforecastTitle); //业绩预告
  671. if (reportCount > 0) aryTitle.push('公告数量:' + reportCount);
  672. if (researchCouunt > 0) aryTitle.push('机构调研次数:' + researchCouunt);
  673. if (tradeDetailCount > 0) aryTitle.push('龙虎榜上榜次数:' + tradeDetailCount);
  674. if (invesotrCount > 0) aryTitle.push('互动易数量:' + invesotrCount);
  675. if (blockTradeCount > 0) aryTitle.push('大宗交易次数:' + blockTradeCount);
  676. if (policyData) //策略选股
  677. {
  678. for (let i in policyData.ExtendData) //显示满足的策略
  679. {
  680. aryTitle.push(policyData.ExtendData[i].Name);
  681. }
  682. }
  683. var maxWidth = 0, textBGHeight = 0;
  684. for (let i in aryTitle) {
  685. var item = aryTitle[i];
  686. var textWidth = this.Canvas.measureText(item).width + 2; //后空2个像素
  687. if (maxWidth < textWidth) maxWidth = textWidth;
  688. textBGHeight += this.InfoTextHeight;
  689. }
  690. this.Canvas.fillStyle = this.InfoTextBGColor;
  691. if (isHScreen) this.Canvas.fillRect(position.Right - maxWidth, position.Top, maxWidth + 2, textBGHeight + 2);
  692. else this.Canvas.fillRect(position.Right - maxWidth, position.Top, maxWidth + 2, textBGHeight + 2);
  693. for (let i in aryTitle) {
  694. var item = aryTitle[i];
  695. this.DrawInfoText(item, position);
  696. }
  697. }
  698. this.HSCreenKLineInfoDraw = function (date) {
  699. this.Canvas.save();
  700. this.KLineInfoDraw(date);
  701. this.Canvas.restore();
  702. }
  703. this.GetColor = function (price, yclse) {
  704. if (price > yclse) return this.UpColor;
  705. else if (price < yclse) return this.DownColor;
  706. else return this.UnchagneColor;
  707. }
  708. this.DrawInfoText = function (title, position) {
  709. if (!title) return true;
  710. this.Canvas.textAlign = "right";
  711. this.Canvas.textBaseline = "top";
  712. this.Canvas.fillStyle = this.InfoTextColor;
  713. this.Canvas.fillText(title, position.Right, position.Top);
  714. position.Top += this.InfoTextHeight;
  715. return true;
  716. }
  717. this.DrawKLineText = function (title, color, position, isShow)
  718. {
  719. if (!title) return true;
  720. var isHScreen = this.Frame.IsHScreen === true;
  721. var right = this.Frame.ChartBorder.GetRight();
  722. if (isHScreen) right = this.Frame.ChartBorder.GetHeight();
  723. this.Canvas.fillStyle = color;
  724. var textWidth = this.Canvas.measureText(title).width;
  725. if (position.Left + textWidth > right) return false;
  726. if (!(isShow === false)) this.Canvas.fillText(title, position.Left, position.Bottom, textWidth);
  727. position.Left += textWidth + this.SpaceWidth;
  728. return true;
  729. }
  730. }
  731. //分时图标题
  732. function DynamicMinuteTitlePainting()
  733. {
  734. this.newMethod = DynamicKLineTitlePainting; //派生
  735. this.newMethod();
  736. delete this.newMethod;
  737. this.YClose;
  738. this.IsShowDate = false; //标题是否显示日期
  739. this.IsShowName = true; //标题是否显示股票名字
  740. this.Symbol;
  741. this.UpperSymbol;
  742. this.LastShowData; //保存最后显示的数据 给tooltip用
  743. this.ClassName ='DynamicMinuteTitlePainting';
  744. this.SpaceWidth = 2;
  745. this.IsShowAveragePrice=true; //是否显示均线价格
  746. this.GetCurrentKLineData = function () //获取当天鼠标位置所在的K线数据
  747. {
  748. if (this.LastShowData) return this.LastShowData;
  749. if (this.CursorIndex == null || !this.Data) return null;
  750. if (this.Data.length <= 0) return null;
  751. var index = Math.abs(this.CursorIndex);
  752. index = parseInt(index.toFixed(0));
  753. var dataIndex = this.Data.DataOffset + index;
  754. if (dataIndex >= this.Data.Data.length) dataIndex = this.Data.Data.length - 1;
  755. if (dataIndex < 0) return null;
  756. var item = this.Data.Data[dataIndex];
  757. return item;
  758. }
  759. this.SendUpdateUIMessage = function (funcName) //通知外面 标题变了
  760. {
  761. if (!this.UpdateUICallback) return;
  762. var sendData =
  763. {
  764. TitleName: '分钟标题', CallFunction: funcName, Stock: { Name: this.Name, Symbol: this.Symbol, },
  765. Rect:
  766. {
  767. Left: this.Frame.ChartBorder.GetLeft(), Right: this.Frame.ChartBorder.GetRight(),
  768. Top: 0, Bottom: this.Frame.ChartBorder.GetTop(),
  769. }
  770. };
  771. //有数据
  772. if (this.Data && this.Data.Data && this.Data.Data.length > 0) {
  773. let index = this.Data.Data.length - 1; //默认最后1分钟的数据
  774. if (this.CursorIndex) {
  775. let cursorIndex = Math.abs(this.CursorIndex - 0.5);
  776. cursorIndex = parseInt(cursorIndex.toFixed(0));
  777. index = this.Data.DataOffset + cursorIndex;
  778. if (index >= this.Data.Data.length) index = this.Data.Data.length - 1;
  779. }
  780. if (index >= 0) {
  781. let item = this.Data.Data[index];
  782. this.LastShowData = item;
  783. sendData.Stock.Data =
  784. {
  785. Time: item.Time, Close: item.Close, AvPrice: item.AvPrice,
  786. Vol: item.Vol, Amount: item.Amount
  787. }
  788. if (item.Time) sendData.Stock.Time = item.Time; //分钟K线才有时间
  789. }
  790. }
  791. this.UpdateUICallback(sendData);
  792. }
  793. this.DrawTitle = function ()
  794. {
  795. this.UpperSymbol = this.Symbol ? this.Symbol.toUpperCase() : '';
  796. this.SendUpdateUIMessage('DrawTitle');
  797. this.OnDrawEventCallback(null, "DynamicMinuteTitlePainting::DrawTitle");
  798. }
  799. this.GetDecimal = function (symbol)
  800. {
  801. return JSCommonCoordinateData.GetfloatPrecision(symbol);//价格小数位数
  802. }
  803. this.DrawMulitLine = function (item) //画多行
  804. {
  805. var leftSpace = 5;
  806. var bottomSpace = 2;
  807. var left = this.Frame.ChartBorder.GetLeft() + leftSpace;;
  808. var right = this.Frame.ChartBorder.GetRight();
  809. var width = this.Frame.ChartBorder.GetWidth();
  810. var height = this.Frame.ChartBorder.GetTop();
  811. var defaultfloatPrecision = this.GetDecimal(this.Symbol); //价格小数位数
  812. var itemHeight = (height - bottomSpace) / this.LineCount;
  813. var bottom = itemHeight;
  814. this.Canvas.textAlign = "left";
  815. this.Canvas.textBaseline = "bottom";
  816. this.Canvas.font = this.Font;
  817. this.Canvas.fillStyle = this.UnchagneColor;
  818. this.Canvas.fillStyle = this.UnchagneColor;
  819. var text = IFrameSplitOperator.FormatDateTimeString(item.DateTime, this.IsShowDate ? 'YYYY-MM-DD' : 'HH-MM');
  820. var timeWidth = this.Canvas.measureText(text).width + 5; //后空5个像素
  821. this.Canvas.fillText(text, left, bottom, timeWidth);
  822. if (this.IsShowDate) {
  823. var text = IFrameSplitOperator.FormatDateTimeString(item.DateTime, 'HH-MM');
  824. this.Canvas.fillText(text, left, bottom + itemHeight, timeWidth);
  825. }
  826. var itemWidth = (width - leftSpace - timeWidth) / 2;
  827. left += timeWidth;
  828. if (item.Close != null) {
  829. this.Canvas.fillStyle = this.GetColor(item.Close, this.YClose);
  830. var text = g_JSChartLocalization.GetText('Tooltip-Price', this.LanguageID) + item.Close.toFixed(defaultfloatPrecision);
  831. this.Canvas.fillText(text, left, bottom, itemWidth);
  832. left += itemWidth;
  833. }
  834. if (item.Increase != null) {
  835. this.Canvas.fillStyle = this.GetColor(item.Increase, 0);
  836. var text = g_JSChartLocalization.GetText('Tooltip-Increase', this.LanguageID) + item.Increase.toFixed(2) + '%';
  837. this.Canvas.fillText(text, left, bottom, itemWidth);
  838. left += itemWidth;
  839. }
  840. bottom += itemHeight; //换行
  841. var left = this.Frame.ChartBorder.GetLeft() + leftSpace + timeWidth;
  842. this.Canvas.fillStyle = this.VolColor;
  843. var text = g_JSChartLocalization.GetText('Tooltip-Vol', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Vol, 2, this.LanguageID);
  844. this.Canvas.fillText(text, left, bottom, itemWidth);
  845. left += itemWidth;
  846. this.Canvas.fillStyle = this.AmountColor;
  847. var text = g_JSChartLocalization.GetText('Tooltip-Amount', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Amount, 2, this.LanguageID);
  848. this.Canvas.fillText(text, left, bottom, itemWidth);
  849. left += itemWidth;
  850. }
  851. this.GetFormatTitle=function(data)
  852. {
  853. if (!data || !data.Data) return null;
  854. var item=data.Data;
  855. var defaultfloatPrecision = this.GetDecimal(this.Symbol); //价格小数位数
  856. var upperSymbol=this.Symbol.toUpperCase();
  857. var isFutures=MARKET_SUFFIX_NAME.IsFutures(upperSymbol); //期货
  858. var aryText=[];
  859. var yClose=item.YClose;
  860. if (isFutures && IFrameSplitOperator.IsNumber(item.YClearing)) yClose=item.YClearing;
  861. if (this.IsShowName) aryText.push({ Text:this.Name, Color:this.NameColor });
  862. var text = IFrameSplitOperator.FormatDateTimeString(item.DateTime, this.IsShowDate ? 'YYYY-MM-DD HH-MM' : 'HH-MM');
  863. aryText.push({ Text:text, Color:this.DateTimeColor });
  864. if (IFrameSplitOperator.IsNumber(item.Close))
  865. {
  866. var color = this.GetColor(item.Close, yClose);
  867. var text = g_JSChartLocalization.GetText('MTitle-Close', this.LanguageID) + item.Close.toFixed(defaultfloatPrecision);
  868. aryText.push({ Text:text, Color:color });
  869. }
  870. if (IFrameSplitOperator.IsNumber(item.Increase))
  871. {
  872. var color = this.GetColor(item.Increase, 0);
  873. var text = g_JSChartLocalization.GetText('MTitle-Increase', this.LanguageID) + item.Increase.toFixed(2) + '%';
  874. aryText.push({ Text:text, Color:color });
  875. }
  876. if (IFrameSplitOperator.IsNumber(item.AvPrice) && this.IsShowAveragePrice==true)
  877. {
  878. var color = this.GetColor(item.AvPrice, yClose);
  879. var text = g_JSChartLocalization.GetText('MTitle-AvPrice', this.LanguageID) + item.AvPrice.toFixed(defaultfloatPrecision);
  880. aryText.push({ Text:text, Color:color });
  881. }
  882. if (IFrameSplitOperator.IsNumber(item.Vol))
  883. {
  884. var text = g_JSChartLocalization.GetText('MTitle-Vol', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Vol, 2, this.LanguageID);
  885. aryText.push({ Text:text, Color:this.VolColor });
  886. }
  887. if (IFrameSplitOperator.IsNumber(item.Amount))
  888. {
  889. var text = g_JSChartLocalization.GetText('MTitle-Amount', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Amount, 2, this.LanguageID);
  890. aryText.push({ Text:text, Color:this.AmountColor });
  891. }
  892. if (MARKET_SUFFIX_NAME.IsChinaFutures(this.UpperSymbol) && IFrameSplitOperator.IsNumber(item.Position))
  893. {
  894. var text = g_JSChartLocalization.GetText('MTitle-Position', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Position, 2, this.LanguageID);
  895. aryText.push({ Text:text, Color:this.VolColor });
  896. }
  897. return { AryText:aryText };
  898. }
  899. this.DrawItem = function (item)
  900. {
  901. var isHScreen = this.Frame.IsHScreen === true;
  902. var left = this.Frame.ChartBorder.GetLeft();;
  903. var bottom = this.Frame.ChartBorder.GetTop() - this.Frame.ChartBorder.Top / 2;
  904. var right = this.Frame.ChartBorder.GetRight();
  905. var defaultfloatPrecision = this.GetDecimal(this.Symbol); //价格小数位数
  906. if (isHScreen)
  907. {
  908. if (this.Frame.ChartBorder.Right < 5) return;
  909. var left = 2;
  910. var bottom = this.Frame.ChartBorder.Right / 2; //上下居中显示
  911. var right = this.Frame.ChartBorder.GetHeight();
  912. var xText = this.Frame.ChartBorder.GetChartWidth();
  913. var yText = this.Frame.ChartBorder.GetTop();
  914. this.Canvas.translate(xText, yText);
  915. this.Canvas.rotate(90 * Math.PI / 180);
  916. }
  917. else
  918. {
  919. if (bottom < 5) return;
  920. }
  921. this.Canvas.textAlign = "left";
  922. this.Canvas.textBaseline = "middle";
  923. this.Canvas.font = this.Font;
  924. var position = { Left: left, Bottom: bottom, IsHScreen: isHScreen };
  925. var titleData=this.GetFormatTitle({ Data:item });
  926. if (titleData && IFrameSplitOperator.IsNonEmptyArray(titleData.AryText))
  927. {
  928. for(var i=0;i<titleData.AryText.length;++i)
  929. {
  930. var item=titleData.AryText[i];
  931. if (!this.DrawMinuteText(item.Text, item.Color, position, true)) break;
  932. if (IFrameSplitOperator.IsNumber(item.LeftSpace)) position.Left+=item.LeftSpace;
  933. }
  934. }
  935. /*
  936. if (this.IsShowName)
  937. {
  938. if (!this.DrawMinuteText(this.Name, this.NameColor, position, true)) return;
  939. }
  940. this.Canvas.fillStyle = this.UnchagneColor;
  941. var text = IFrameSplitOperator.FormatDateTimeString(item.DateTime, this.IsShowDate ? 'YYYY-MM-DD HH-MM' : 'HH-MM');
  942. if (!this.DrawMinuteText(text, this.DateTimeColor, position)) return;
  943. if (IFrameSplitOperator.IsNumber(item.Close))
  944. {
  945. var color = this.GetColor(item.Close, this.YClose);
  946. var text = g_JSChartLocalization.GetText('MTitle-Close', this.LanguageID) + item.Close.toFixed(defaultfloatPrecision);
  947. if (!this.DrawMinuteText(text, color, position)) return;
  948. }
  949. if (IFrameSplitOperator.IsNumber(item.Increase))
  950. {
  951. var color = this.GetColor(item.Increase, 0);
  952. var text = g_JSChartLocalization.GetText('MTitle-Increase', this.LanguageID) + item.Increase.toFixed(2) + '%';
  953. if (!this.DrawMinuteText(text, color, position)) return;
  954. }
  955. if (IFrameSplitOperator.IsNumber(item.AvPrice) && this.IsShowAveragePrice==true)
  956. {
  957. var color = this.GetColor(item.AvPrice, this.YClose);
  958. var text = g_JSChartLocalization.GetText('MTitle-AvPrice', this.LanguageID) + item.AvPrice.toFixed(defaultfloatPrecision);
  959. if (!this.DrawMinuteText(text, color, position)) return;
  960. }
  961. if (IFrameSplitOperator.IsNumber(item.Vol))
  962. {
  963. var text = g_JSChartLocalization.GetText('MTitle-Vol', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Vol, 2, this.LanguageID);
  964. if (!this.DrawMinuteText(text, this.VolColor, position)) return;
  965. }
  966. if (IFrameSplitOperator.IsNumber(item.Amount))
  967. {
  968. var text = g_JSChartLocalization.GetText('MTitle-Amount', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Amount, 2, this.LanguageID);
  969. if (!this.DrawMinuteText(text, this.AmountColor, position)) return;
  970. }
  971. if (MARKET_SUFFIX_NAME.IsChinaFutures(this.UpperSymbol) && IFrameSplitOperator.IsNumber(item.Position))
  972. {
  973. var text = g_JSChartLocalization.GetText('MTitle-Position', this.LanguageID) + IFrameSplitOperator.FormatValueString(item.Position, 2, this.LanguageID);
  974. if (!this.DrawMinuteText(text, this.VolColor, position)) return;
  975. }
  976. */
  977. }
  978. this.FullDraw=function()
  979. {
  980. this.Draw();
  981. }
  982. this.Draw = function ()
  983. {
  984. this.UpperSymbol = this.Symbol ? this.Symbol.toUpperCase() : '';
  985. this.LastShowData = null;
  986. this.SendUpdateUIMessage('Draw');
  987. if (!this.IsShow) return;
  988. if (this.CursorIndex == null || !this.Data || !this.Data.Data || this.Data.Data.length <= 0)
  989. {
  990. this.OnDrawEventCallback(null,"DynamicMinuteTitlePainting::Draw");
  991. return;
  992. }
  993. if (this.TextSpace>=0)
  994. {
  995. this.SpaceWidth=this.TextSpace;
  996. }
  997. else
  998. {
  999. this.Canvas.font = this.Font;
  1000. this.SpaceWidth = this.Canvas.measureText(' ').width;
  1001. }
  1002. var index = this.CursorIndex;
  1003. index = parseInt(index.toFixed(0));
  1004. var dataIndex = index + this.Data.DataOffset;
  1005. if (dataIndex >= this.Data.Data.length) dataIndex = this.Data.Data.length - 1;
  1006. var item = this.Data.Data[dataIndex];
  1007. this.LastShowData = item;
  1008. this.OnDrawEventCallback(item, "DynamicMinuteTitlePainting::Draw");
  1009. if (this.LineCount > 1 && !(this.Frame.IsHScreen === true))
  1010. {
  1011. this.DrawMulitLine(item);
  1012. return;
  1013. }
  1014. this.Canvas.save();
  1015. this.DrawItem(item);
  1016. this.Canvas.restore();
  1017. }
  1018. this.DrawMinuteText = function (title, color, position, isShow)
  1019. {
  1020. if (!title) return true;
  1021. var isHScreen = this.Frame.IsHScreen === true;
  1022. var right = this.Frame.ChartBorder.GetRight();
  1023. if (isHScreen) right = this.Frame.ChartBorder.GetHeight();
  1024. this.Canvas.fillStyle = color;
  1025. var textWidth = this.Canvas.measureText(title).width;
  1026. if (position.Left + textWidth > right) return false;
  1027. if (!(isShow === false)) this.Canvas.fillText(title, position.Left, position.Bottom, textWidth);
  1028. position.Left += textWidth + this.SpaceWidth;
  1029. return true;
  1030. }
  1031. }
  1032. //字符串输出格式
  1033. var STRING_FORMAT_TYPE =
  1034. {
  1035. DEFAULT: 1, //默认 2位小数 单位自动转化 (万 亿)
  1036. ORIGINAL: 2, //原始数据
  1037. THOUSANDS: 21, //千分位分割
  1038. };
  1039. function DynamicTitleData(data, name, color) //指标标题数据
  1040. {
  1041. this.Data = data;
  1042. this.Name = name;
  1043. this.Color = color; //字体颜色
  1044. this.DataType; //数据类型
  1045. this.ChartClassName;
  1046. this.StringFormat = STRING_FORMAT_TYPE.DEFAULT; //字符串格式
  1047. this.FloatPrecision = 2; //小数位数
  1048. this.GetTextCallback; //自定义数据转文本回调
  1049. this.IsShow=true;
  1050. }
  1051. //指标标题
  1052. function DynamicChartTitlePainting()
  1053. {
  1054. this.newMethod = IChartTitlePainting; //派生
  1055. this.newMethod();
  1056. delete this.newMethod;
  1057. this.IsDynamic = true;
  1058. this.Data = new Array();
  1059. this.Explain;
  1060. this.TitleBG; //标题背景色
  1061. this.TitleBGHeight = 20; //标题背景色高度
  1062. this.TitleAlign = 'middle';//对其方式
  1063. this.TitleBottomDistance = 1; //标题靠底部输出的时候 字体和底部的间距
  1064. this.Text = new Array(); //副标题 Text:'文本', Color:'颜色'
  1065. this.EraseRect;
  1066. this.EraseColor = g_JSChartResource.BGColor; //用来擦出的背景色
  1067. this.TitleRect; //指标名字显示区域
  1068. this.IsDrawTitleBG=false; //是否绘制指标名字背景色
  1069. this.BGColor=g_JSChartResource.IndexTitleBGColor; //指标名字背景颜色
  1070. this.BGBorderColor=g_JSChartResource.IndexTitleBorderColor;
  1071. this.TitleButtonConfig=
  1072. {
  1073. Mergin:
  1074. {
  1075. Left:g_JSChartResource.IndexTitleButton.Mergin.Left, Top:g_JSChartResource.IndexTitleButton.Mergin.Top,
  1076. Bottom:g_JSChartResource.IndexTitleButton.Mergin.Bottom, Right:g_JSChartResource.IndexTitleButton.Mergin.Right
  1077. },
  1078. Font:g_JSChartResource.IndexTitleButton.Font,
  1079. RightSpace:g_JSChartResource.IndexTitleButton.RightSpace
  1080. };
  1081. this.TitleColor = g_JSChartResource.IndexTitleColor; //指标名字颜色
  1082. this.ArgumentsText; //参数信息
  1083. this.IsShowIndexName = true; //是否显示指标名字
  1084. this.IsShowNameArrow=false;
  1085. this.NameArrowConfig=CloneData(g_JSChartResource.IndexTitle.NameArrow);
  1086. this.ParamSpace = 2; //参数显示的间距
  1087. this.TitleSpace=2; //指标名字和参数之间的间距
  1088. this.OutName=null; //动态标题
  1089. this.IsFullDraw=true; //手势离开屏幕以后是否显示最后的价格
  1090. this.IsShowUpDownArrow=true; //指标数据是否显示 上涨下跌箭头
  1091. this.TitleArrowType=0; //指标数据上涨下跌箭头类型 0=独立颜色 1=跟指标颜色一致
  1092. this.OverlayIndex=new Map(); //叠加指标 key=Identify value={ Data:数据, Title:标题, Identify:标识}
  1093. this.IsShowOverlayIndexName=true;
  1094. this.OverlayIndexType={ LineSpace:1, BGColor:g_JSChartResource.OverlayIndexTitleBGColor }; //Position 0=主图指标后面显示 1=叠加指标单行显示
  1095. this.DynamicTitle={ OutName:null, OutValue:null };
  1096. this.OverlayDynamicTitle=new Map(); //key , value={ OutName, OutValue }
  1097. this.IsShowMainIndexTitle=true; //是否显示主图指标标题
  1098. this.UpDownArrowConfig=
  1099. {
  1100. UpColor:g_JSChartResource.IndexTitle.UpDownArrow.UpColor,
  1101. DownColor:g_JSChartResource.IndexTitle.UpDownArrow.DownColor,
  1102. UnchangeColor:g_JSChartResource.IndexTitle.UpDownArrow.UnchangeColor
  1103. };
  1104. this.SetDynamicTitleData=function(outName, args, data)
  1105. {
  1106. if (!data.OutName) data.OutName=new Map();
  1107. else data.OutName.clear();
  1108. if (!data.OutValue) data.OutValue=new Map();
  1109. else data.OutValue.clear();
  1110. var mapArgs=new Map();
  1111. for(var i in args)
  1112. {
  1113. var item=args[i];
  1114. mapArgs.set(`{${item.Name}}`, item);
  1115. }
  1116. for(var i in outName)
  1117. {
  1118. var item=outName[i];
  1119. if (item.DynamicName)
  1120. {
  1121. var aryFond = item.DynamicName.match(/{\w*}/i);
  1122. if (!aryFond || aryFond.length<=0)
  1123. {
  1124. data.OutName.set(item.Name, item.DynamicName);
  1125. }
  1126. else
  1127. {
  1128. var dyName=item.DynamicName;
  1129. var bFind=true;
  1130. for(var j=0;j<aryFond.length;++j)
  1131. {
  1132. var findItem=aryFond[j];
  1133. if (mapArgs.has(findItem))
  1134. {
  1135. var value=mapArgs.get(findItem).Value;
  1136. dyName=dyName.replace(findItem,value.toString());
  1137. }
  1138. else
  1139. {
  1140. bFind=false;
  1141. break;
  1142. }
  1143. }
  1144. if (bFind) data.OutName.set(item.Name, dyName);
  1145. }
  1146. }
  1147. if (item.DynamicValue)
  1148. {
  1149. data.OutValue.set(item.Name, item.DynamicValue);
  1150. }
  1151. }
  1152. }
  1153. this.SetDynamicTitle=function(outName, args, overlayID)
  1154. {
  1155. if (IFrameSplitOperator.IsString(overlayID))
  1156. {
  1157. var dynamicTitle=null;
  1158. if (this.OverlayDynamicTitle.has(overlayID))
  1159. {
  1160. dynamicTitle=this.OverlayDynamicTitle.get(overlayID);
  1161. }
  1162. else
  1163. {
  1164. dynamicTitle={ OutName:null, OutValue:null };
  1165. this.OverlayDynamicTitle.set(overlayID, dynamicTitle);
  1166. }
  1167. this.SetDynamicTitleData(outName, args, dynamicTitle);
  1168. }
  1169. else
  1170. {
  1171. this.SetDynamicTitleData(outName, args, this.DynamicTitle);
  1172. }
  1173. }
  1174. this.GetDynamicOutName=function(key, overlayID)
  1175. {
  1176. if (IFrameSplitOperator.IsString(overlayID))
  1177. {
  1178. if (!this.OverlayDynamicTitle.has(overlayID)) return null;
  1179. var dynamicTitle=this.OverlayDynamicTitle.get(overlayID);
  1180. var outName=dynamicTitle.OutName;
  1181. }
  1182. else
  1183. {
  1184. var outName=this.DynamicTitle.OutName;
  1185. }
  1186. if (!outName || outName.size<=0) return null;
  1187. if (!outName.has(key)) return null;
  1188. return outName.get(key);
  1189. }
  1190. this.IsClickTitle=function(x,y) //是否点击了指标标题
  1191. {
  1192. if (!this.TitleRect) return false;
  1193. if (x>this.TitleRect.Left && x<this.TitleRect.Left+this.TitleRect.Width && y>this.TitleRect.Top && y<this.TitleRect.Top+this.TitleRect.Height)
  1194. {
  1195. return true;
  1196. }
  1197. return false;
  1198. }
  1199. this.FormatValue = function (value, item)
  1200. {
  1201. if (item.StringFormat == STRING_FORMAT_TYPE.DEFAULT)
  1202. return IFrameSplitOperator.FormatValueString(value, item.FloatPrecision, this.LanguageID);
  1203. else if (item.StringFormat = STRING_FORMAT_TYPE.THOUSANDS)
  1204. return IFrameSplitOperator.FormatValueThousandsString(value, item.FloatPrecision);
  1205. else if (item.StringFormat == STRING_FORMAT_TYPE.ORIGINAL)
  1206. return value.toFixed(item.FloatPrecision).toString();
  1207. }
  1208. this.FormatMultiReport = function (data, format)
  1209. {
  1210. var text = "";
  1211. for (var i in data) {
  1212. var item = data[i];
  1213. let quarter = item.Quarter;
  1214. let year = item.Year;
  1215. let value = item.Value;
  1216. if (text.length > 0) text += ',';
  1217. text += year.toString();
  1218. switch (quarter) {
  1219. case 1:
  1220. text += '一季报 ';
  1221. break;
  1222. case 2:
  1223. text += '半年报 ';
  1224. break;
  1225. case 3:
  1226. text += '三季报 ';
  1227. break;
  1228. case 4:
  1229. text += '年报 ';
  1230. break;
  1231. }
  1232. text += this.FormatValue(value, format);
  1233. }
  1234. return text;
  1235. }
  1236. //多变量输出
  1237. this.FromatStackedBarTitle=function(aryBar, dataInfo)
  1238. {
  1239. if (!IFrameSplitOperator.IsNonEmptyArray(aryBar)) return null;
  1240. if (!IFrameSplitOperator.IsNonEmptyArray(dataInfo.Color)) return null;
  1241. var aryText=[];
  1242. for(var i=0;i<aryBar.length;++i)
  1243. {
  1244. var value=aryBar[i];
  1245. if (!IFrameSplitOperator.IsNumber(value)) continue;
  1246. var item={ Text:value.toFixed(2) };
  1247. if (dataInfo.Name && dataInfo.Name[i]) item.Name=dataInfo.Name[i];
  1248. item.Color=dataInfo.Color[i];
  1249. aryText.push(item);
  1250. }
  1251. if (aryText.length<=0) return null;
  1252. return aryText;
  1253. }
  1254. this.SendUpdateUIMessage = function (funcName) //通知外面 标题变了
  1255. {
  1256. if (!this.UpdateUICallback) return;
  1257. var sendData = {
  1258. TitleName: '指标标题', CallFunction: funcName,
  1259. TitleData: { Title: this.Title, Identify: this.Frame.Identify, Data: [] },
  1260. Rect: //标题的位置
  1261. {
  1262. Top: this.Frame.ChartBorder.GetTop(), Left: this.Frame.ChartBorder.GetLeft(),
  1263. Right: this.Frame.ChartBorder.GetRight(), Bottom: this.Frame.ChartBorder.GetBottom()
  1264. }
  1265. };
  1266. for (var i in this.Data) {
  1267. var item = this.Data[i];
  1268. if (!item || !item.Data || !item.Data.Data) continue;
  1269. if (item.Data.Data.length <= 0) continue;
  1270. var titleItem = { Name: item.Name, Color: item.Color };
  1271. if (item.DataType) titleItem.DataType = item.DataType;
  1272. if (item.DataType == "StraightLine") //直线只有1个数据
  1273. {
  1274. titleItem.Value = item.Data.Data[0];
  1275. }
  1276. else {
  1277. var index = item.Data.Data.length - 1;
  1278. if (this.CursorIndex != null) {
  1279. var cursorIndex = Math.abs(this.CursorIndex - 0.5);
  1280. cursorIndex = parseInt(cursorIndex.toFixed(0));
  1281. index = item.Data.DataOffset + cursorIndex
  1282. }
  1283. if (index >= item.Data.Data.length) index = item.Data.Data.length - 1;
  1284. titleItem.Value = item.Data.Data[index];
  1285. }
  1286. sendData.TitleData.Data.push(titleItem);
  1287. }
  1288. //console.log('[DynamicChartTitlePainting::SendUpdateUIMessage', sendData);
  1289. this.UpdateUICallback(sendData);
  1290. }
  1291. this.FullDraw=function()
  1292. {
  1293. this.EraseRect = null;
  1294. this.TitleRect=null;
  1295. if (this.Frame.IsMinSize) return;
  1296. this.OnDrawTitleEvent();
  1297. if (this.Frame.ChartBorder.TitleHeight < 5) return;
  1298. if (this.Frame.IsShowTitle == false) return;
  1299. this.IsDrawTitleBG=this.Frame.IsDrawTitleBG;
  1300. this.IsShowIndexName = this.Frame.IsShowIndexName;
  1301. this.IsShowNameArrow=this.Frame.IsShowNameArrow;
  1302. this.ParamSpace = this.Frame.IndexParamSpace;
  1303. this.TitleSpace=this.Frame.IndexTitleSpace;
  1304. this.IsShowUpDownArrow=this.Frame.IsShowTitleArrow;
  1305. this.TitleArrowType=this.Frame.TitleArrowType;
  1306. if (this.Frame.IsHScreen === true)
  1307. {
  1308. this.Canvas.save();
  1309. this.DrawItem(true,true);
  1310. this.DrawOverlayIndexSingleLine();
  1311. this.Canvas.restore();
  1312. /*
  1313. //测试用
  1314. if (this.TitleRect)
  1315. {
  1316. this.Canvas.strokeStyle='rgba(200,0,50,1)';
  1317. this.Canvas.strokeRect(ToFixedPoint(this.TitleRect.Left),ToFixedPoint(this.TitleRect.Top),ToFixedRect(this.TitleRect.Width),ToFixedRect(this.TitleRect.Height));
  1318. }
  1319. */
  1320. return;
  1321. }
  1322. this.DrawItem(true,true);
  1323. this.DrawOverlayIndexSingleLine();
  1324. }
  1325. this.DrawTitle = function ()
  1326. {
  1327. this.IsDrawTitleBG=this.Frame.IsDrawTitleBG;
  1328. this.EraseRect = null;
  1329. this.TitleRect=null;
  1330. this.SendUpdateUIMessage('DrawTitle');
  1331. if (this.Frame.ChartBorder.TitleHeight < 5) return;
  1332. if (this.Frame.IsShowTitle == false) return;
  1333. this.IsShowIndexName = this.Frame.IsShowIndexName;
  1334. this.ParamSpace = this.Frame.IndexParamSpace;
  1335. if (this.Frame.IsHScreen === true)
  1336. {
  1337. this.Canvas.save();
  1338. this.DrawItem(true,false);
  1339. this.Canvas.restore();
  1340. return;
  1341. }
  1342. this.DrawItem(true,false);
  1343. }
  1344. this.EraseTitle = function ()
  1345. {
  1346. if (!this.EraseRect) return;
  1347. this.Canvas.fillStyle = this.EraseColor;
  1348. this.Canvas.fillRect(this.EraseRect.Left, this.EraseRect.Top, this.EraseRect.Width, this.EraseRect.Height);
  1349. }
  1350. this.Draw = function ()
  1351. {
  1352. this.TitleRect=null;
  1353. this.SendUpdateUIMessage('Draw');
  1354. if (this.CursorIndex == null) return;
  1355. if (!this.Data) return;
  1356. if (this.Frame.ChartBorder.TitleHeight < 5) return;
  1357. if (this.Frame.IsShowTitle == false) return;
  1358. this.IsShowIndexName = this.Frame.IsShowIndexName;
  1359. this.IsShowNameArrow=this.Frame.IsShowNameArrow;
  1360. this.ParamSpace = this.Frame.IndexParamSpace;
  1361. this.TitleSpace=this.Frame.IndexTitleSpace;
  1362. if (this.Frame.IsHScreen === true)
  1363. {
  1364. this.Canvas.save();
  1365. this.DrawItem(false,true);
  1366. this.Canvas.restore();
  1367. return;
  1368. }
  1369. this.DrawItem(false,true);
  1370. }
  1371. this.GetTitleItem=function(item, isShowLastData, titleIndex)
  1372. {
  1373. if (!item || !item.Data || !item.Data.Data) return null;
  1374. if (item.Data.Data.length <= 0) return null;
  1375. if (item.IsShow==false) return null;
  1376. var valueText = null;
  1377. var aryText=null;
  1378. var value = null;
  1379. var dataIndex=-1;
  1380. if (item.DataType == "StraightLine") //直线只有1个数据
  1381. {
  1382. value = item.Data.Data[0];
  1383. valueText = this.FormatValue(value, item);
  1384. }
  1385. else
  1386. {
  1387. var index = this.CursorIndex - 0.5;
  1388. if (index<0) index=0;
  1389. index = parseInt(index.toFixed(0));
  1390. var dataIndex=item.Data.DataOffset+index;
  1391. if (dataIndex >= item.Data.Data.length) return null;
  1392. value = item.Data.Data[dataIndex];
  1393. if (value == null) return null;
  1394. if (item.DataType == "HistoryData-Vol")
  1395. {
  1396. value = value.Vol;
  1397. valueText = this.FormatValue(value, item);
  1398. }
  1399. else if (item.DataType == "MultiReport")
  1400. {
  1401. valueText = this.FormatMultiReport(value, item);
  1402. }
  1403. else if (item.DataType=="ChartStackedBar")
  1404. {
  1405. aryText=this.FromatStackedBarTitle(value, item);
  1406. if (!aryText) return null;
  1407. }
  1408. else
  1409. {
  1410. if (this.GetEventCallback)
  1411. {
  1412. var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_FORMAT_INDEX_OUT_TEXT);
  1413. if (event)
  1414. {
  1415. var data=
  1416. {
  1417. Item:item, Index:titleIndex, Data:this.Data, FrameID:this.Frame.Identify,
  1418. DataIndex:dataIndex, Value:value,
  1419. Out:null
  1420. };
  1421. event.Callback(event,data,this);
  1422. if (data.Out) return data.Out;
  1423. }
  1424. }
  1425. var arrowSuper=null; //独立颜色
  1426. if (this.IsShowUpDownArrow)
  1427. {
  1428. var preValue=null;
  1429. if (dataIndex-1>=0) preValue=item.Data.Data[dataIndex-1];
  1430. if (IFrameSplitOperator.IsNumber(preValue))
  1431. {
  1432. if (preValue>value) arrowSuper={ Text:'↓', TextColor:this.UpDownArrowConfig.DownColor };
  1433. else if (preValue<value) arrowSuper={ Text:'↑', TextColor:this.UpDownArrowConfig.UpColor};
  1434. else arrowSuper={ Text:'→', TextColor:this.UpDownArrowConfig.UnchangeColor };
  1435. if (this.TitleArrowType==1) arrowSuper.TextColor=item.Color;
  1436. }
  1437. }
  1438. if (item.GetTextCallback) valueText = item.GetTextCallback(value, item);
  1439. else valueText = this.FormatValue(value, item);
  1440. if (arrowSuper)
  1441. {
  1442. var outItem={ Name:null, Text:valueText, Color:item.Color, TextEx:[arrowSuper] };
  1443. if (item.Name)
  1444. {
  1445. var text=item.Name;
  1446. var dyTitle=this.GetDynamicOutName(item.Name); //动态标题
  1447. if (dyTitle) text=dyTitle;
  1448. outItem.Name=text;
  1449. }
  1450. //outItem.BG='rgb(100,100,100)';
  1451. aryText=[outItem];
  1452. valueText=null;
  1453. }
  1454. }
  1455. }
  1456. if (!valueText && !aryText) return null;
  1457. return { Text:valueText, ArrayText:aryText };
  1458. }
  1459. this.DrawItem=function(bDrawTitle, bDrawValue)
  1460. {
  1461. var isHScreen=(this.Frame.IsHScreen === true);
  1462. var left = this.Frame.ChartBorder.GetLeft() + 1;
  1463. var bottom = this.Frame.ChartBorder.GetTop() + this.Frame.ChartBorder.TitleHeight / 2; //上下居中显示
  1464. if (this.TitleAlign == 'bottom') bottom = this.Frame.ChartBorder.GetTopEx() - this.TitleBottomDistance;
  1465. var right = this.Frame.ChartBorder.GetRight();
  1466. var textWidth;
  1467. if (isHScreen)
  1468. {
  1469. let xText = this.Frame.ChartBorder.GetRightTitle();
  1470. let yText = this.Frame.ChartBorder.GetTop();
  1471. this.Canvas.translate(xText, yText);
  1472. this.Canvas.rotate(90 * Math.PI / 180);
  1473. left = 1;
  1474. bottom = -(this.Frame.ChartBorder.TitleHeight / 2); //上下居中显示
  1475. if (this.TitleAlign == 'bottom') bottom = -this.TitleBottomDistance;
  1476. right = this.Frame.ChartBorder.GetHeight();
  1477. }
  1478. this.EraseTitle();
  1479. this.Canvas.textAlign = "left";
  1480. this.Canvas.textBaseline = this.TitleAlign;
  1481. this.Canvas.font = this.Font;
  1482. if (this.TitleBG && this.Title && this.IsShowMainIndexTitle) //指标名称
  1483. {
  1484. textWidth = this.Canvas.measureText(this.Title).width + 2;
  1485. let height = this.Frame.ChartBorder.TitleHeight;
  1486. let top = this.Frame.ChartBorder.GetTop();
  1487. if (height > 20)
  1488. {
  1489. top += (height - 20) / 2 + (height - 45) / 2;
  1490. height = 20;
  1491. }
  1492. if (this.TitleAlign == 'bottom') //底部输出文字
  1493. {
  1494. top = this.Frame.ChartBorder.GetTopEx() - 20;
  1495. if (top < 0) top = 0;
  1496. }
  1497. if (bDrawTitle)
  1498. {
  1499. this.Canvas.fillStyle = this.TitleBG;
  1500. this.Canvas.fillRect(left, top, textWidth, height);
  1501. }
  1502. }
  1503. if (this.Title && this.IsShowIndexName && this.IsShowMainIndexTitle) //指标参数
  1504. {
  1505. const metrics = this.Canvas.measureText(this.Title);
  1506. textWidth = metrics.width + 2;
  1507. if (bDrawTitle)
  1508. {
  1509. if (this.IsDrawTitleBG) //绘制指标名背景色
  1510. {
  1511. if (this.TitleButtonConfig.Font) this.Canvas.font=this.TitleButtonConfig.Font;
  1512. var title=this.Title;
  1513. var textWidth=this.Canvas.measureText(title).width;
  1514. var titleWidth=textWidth+this.TitleButtonConfig.Mergin.Left+this.TitleButtonConfig.Mergin.Right;
  1515. var arrowWidth=0;
  1516. if (this.IsShowNameArrow && this.NameArrowConfig)
  1517. {
  1518. arrowWidth=this.Canvas.measureText(this.NameArrowConfig.Symbol).width;
  1519. titleWidth+=arrowWidth;
  1520. if (IFrameSplitOperator.IsNumber(this.NameArrowConfig.Space)) titleWidth+=this.NameArrowConfig.Space;
  1521. }
  1522. var textHeight=this.Canvas.measureText("擎").width;
  1523. var bgHeight=textHeight+this.TitleButtonConfig.Mergin.Top+this.TitleButtonConfig.Mergin.Bottom;
  1524. var bgWidth=titleWidth;
  1525. this.Canvas.fillStyle=this.BGColor;
  1526. if (isHScreen)
  1527. {
  1528. this.TitleRect=
  1529. {
  1530. Top:this.Frame.ChartBorder.GetTop(),
  1531. Left:this.Frame.ChartBorder.GetRightTitle()+this.Frame.ChartBorder.TitleHeight/2-bgHeight/2,
  1532. Width:bgHeight ,Height:bgWidth
  1533. }; //保存下标题的坐标
  1534. let drawRect={Left:left, Top:-bgHeight-2, Width:bgWidth, Height:bgHeight};
  1535. this.Canvas.fillRect(drawRect.Left,drawRect.Top,drawRect.Width,drawRect.Height);
  1536. if (this.BGBorderColor)
  1537. {
  1538. this.Canvas.strokeStyle=this.BGBorderColor;
  1539. this.Canvas.strokeRect(ToFixedPoint(drawRect.Left),ToFixedPoint(drawRect.Top),ToFixedRect(drawRect.Width),ToFixedRect(drawRect.Height));
  1540. }
  1541. }
  1542. else
  1543. {
  1544. this.TitleRect={ Left:left, Top:bottom-textHeight/2-this.TitleButtonConfig.Mergin.Top, Width:bgWidth, Height:bgHeight }; //保存下标题的坐标
  1545. this.Canvas.fillRect(this.TitleRect.Left,this.TitleRect.Top,this.TitleRect.Width,this.TitleRect.Height);
  1546. if (this.BGBorderColor)
  1547. {
  1548. this.Canvas.strokeStyle=this.BGBorderColor;
  1549. this.Canvas.strokeRect(ToFixedPoint(this.TitleRect.Left),ToFixedPoint(this.TitleRect.Top),ToFixedRect(this.TitleRect.Width),ToFixedRect(this.TitleRect.Height));
  1550. }
  1551. }
  1552. var xText= left+this.TitleButtonConfig.Mergin.Left;
  1553. var yText=bottom-this.TitleButtonConfig.Mergin.Bottom;
  1554. this.Canvas.fillStyle = this.TitleColor;
  1555. this.Canvas.fillText(title, xText, yText, textWidth);
  1556. xText+=textWidth;
  1557. if (this.IsShowNameArrow && this.NameArrowConfig)
  1558. {
  1559. if (IFrameSplitOperator.IsNumber(this.NameArrowConfig.Space)) xText+=this.NameArrowConfig.Space;
  1560. this.Canvas.fillStyle=this.NameArrowConfig.Color;
  1561. this.Canvas.fillText(this.NameArrowConfig.Symbol,xText,yText,arrowWidth);
  1562. }
  1563. textWidth=bgWidth+this.TitleButtonConfig.RightSpace;
  1564. this.Canvas.font=this.Font;
  1565. }
  1566. else
  1567. {
  1568. this.Canvas.fillStyle = this.TitleColor;
  1569. this.Canvas.fillText(this.Title, left, bottom, textWidth);
  1570. }
  1571. }
  1572. left += textWidth;
  1573. left+=this.TitleSpace;
  1574. }
  1575. //指标参数
  1576. if (this.ArgumentsText && this.IsShowIndexName && this.IsShowMainIndexTitle)
  1577. {
  1578. var textWidth=this.Canvas.measureText(this.ArgumentsText).width+2;
  1579. this.Canvas.fillStyle=this.TitleColor;
  1580. this.Canvas.fillText(this.ArgumentsText, left, bottom, textWidth);
  1581. left += textWidth;
  1582. left+=this.TitleSpace;
  1583. }
  1584. if (this.Text && this.Text.length > 0)
  1585. {
  1586. for (let i in this.Text)
  1587. {
  1588. let item = this.Text[i];
  1589. this.Canvas.fillStyle = item.Color;
  1590. textWidth = this.Canvas.measureText(item.Text).width + 2;
  1591. this.Canvas.fillText(item.Text, left, bottom, textWidth);
  1592. left += textWidth;
  1593. }
  1594. }
  1595. if (bDrawValue)
  1596. {
  1597. for (var i=0; i<this.Data.length && this.IsShowMainIndexTitle; ++i)
  1598. {
  1599. var item = this.Data[i];
  1600. var outText=this.GetTitleItem(item, false, i);
  1601. if (!outText) continue;
  1602. var valueText=outText.Text;
  1603. var aryText=outText.ArrayText;
  1604. if (aryText)
  1605. {
  1606. var text;
  1607. for(var k=0;k<aryText.length;++k)
  1608. {
  1609. var titleItem=aryText[k];
  1610. if (titleItem.Name) text=titleItem.Name+":"+titleItem.Text;
  1611. else text=titleItem.Text;
  1612. var textWidth=this.Canvas.measureText(text).width
  1613. if ((left+textWidth)>right) break;
  1614. this.Canvas.fillStyle=titleItem.Color;
  1615. this.Canvas.fillText(text,left,bottom,textWidth);
  1616. left+=textWidth;
  1617. if (IFrameSplitOperator.IsNonEmptyArray(titleItem.TextEx))
  1618. {
  1619. for(var n=0; n<titleItem.TextEx.length; ++n)
  1620. {
  1621. var outItem=titleItem.TextEx[n];
  1622. this.Canvas.fillStyle=outItem.TextColor;
  1623. outItem.Width=this.Canvas.measureText(outItem.Text).width+2;
  1624. if ((left+outItem.Width)>right) break;
  1625. this.Canvas.fillText(outItem.Text,left,bottom,outItem.Width);
  1626. left+=outItem.Width;
  1627. }
  1628. }
  1629. left+=this.ParamSpace;
  1630. }
  1631. }
  1632. else
  1633. {
  1634. var text=valueText;
  1635. if (item.Name)
  1636. {
  1637. var dyTitle=this.GetDynamicOutName(item.Name);
  1638. if (dyTitle) text=dyTitle+ ":" + valueText;
  1639. else text = item.Name + ":" + valueText;
  1640. }
  1641. textWidth = this.Canvas.measureText(text).width + this.ParamSpace; //后空2个像素
  1642. if (textWidth+left>right) break; //画不下了就不画了
  1643. this.Canvas.fillStyle = item.Color;
  1644. this.Canvas.fillText(text, left, bottom, textWidth);
  1645. left += textWidth;
  1646. }
  1647. }
  1648. }
  1649. else
  1650. {
  1651. left += 4;
  1652. var eraseRight = left, eraseLeft = left;
  1653. for (var i in this.Data)
  1654. {
  1655. var item = this.Data[i];
  1656. if (!item || !item.Data || !item.Data.Data) continue;
  1657. if (item.Data.Data.length <= 0) continue;
  1658. var indexName = '●' + item.Name;
  1659. this.Canvas.fillStyle = item.Color;
  1660. textWidth = this.Canvas.measureText(indexName).width + this.ParamSpace;
  1661. if (left + textWidth >= right) break;
  1662. this.Canvas.fillText(indexName, left, bottom, textWidth);
  1663. left += textWidth;
  1664. eraseRight = left;
  1665. }
  1666. if (eraseRight > eraseLeft)
  1667. {
  1668. if (isHScreen)
  1669. {
  1670. this.EraseRect =
  1671. {
  1672. Left: eraseLeft, Right: eraseRight, Top: -(this.Frame.ChartBorder.TitleHeight - 1),
  1673. Width: eraseRight - eraseLeft, Height: this.Frame.ChartBorder.TitleHeight - 2
  1674. };
  1675. }
  1676. else
  1677. {
  1678. this.EraseRect =
  1679. {
  1680. Left: eraseLeft, Right: eraseRight, Top: (this.Frame.ChartBorder.GetTop() + 1),
  1681. Width: eraseRight - eraseLeft, Height: this.Frame.ChartBorder.TitleHeight - 2
  1682. };
  1683. }
  1684. }
  1685. }
  1686. }
  1687. this.OnDrawTitleEvent=function()
  1688. {
  1689. var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_INDEXTITLE_DRAW);
  1690. if (!event) return;
  1691. var data={ Index:null, Data:this.Data ,Title:this.Title, FrameID:this.Frame.Identify };
  1692. if (IFrameSplitOperator.IsNumber(this.CursorIndex))
  1693. {
  1694. var index=Math.abs(this.CursorIndex);
  1695. index=parseInt(index.toFixed(0));
  1696. data.Index=index; //当前屏数据索引
  1697. }
  1698. var border=this.Frame.GetBorder();
  1699. data.Left=border.LeftEx;
  1700. data.Top=border.Top;
  1701. data.Right=border.RightEx;
  1702. event.Callback(event,data,this);
  1703. }
  1704. this.DrawOverlayIndexSingleLine=function() //叠加指标1个指标一行
  1705. {
  1706. if (this.OverlayIndex.size<=0) return;
  1707. var isHScreen=(this.Frame.IsHScreen === true);
  1708. var border=this.Frame.GetBorder();
  1709. var lineSpace=this.OverlayIndexType.LineSpace;
  1710. this.Canvas.textAlign="left";
  1711. this.Canvas.textBaseline="middle";
  1712. this.Canvas.font=this.Font;
  1713. var fontHeight=this.Canvas.measureText("擎").width;
  1714. if (isHScreen)
  1715. {
  1716. var left = 1;
  1717. var top = lineSpace; //上下居中显示
  1718. if (!this.IsShowMainIndexTitle) top-=this.Frame.ChartBorder.TitleHeight;
  1719. var right = this.Frame.ChartBorder.GetHeight();
  1720. }
  1721. else
  1722. {
  1723. var top=border.TopTitle+2;
  1724. if (!this.IsShowMainIndexTitle) top=this.Frame.ChartBorder.GetTop()+2;
  1725. var left=border.Left+1;
  1726. var right=border.Right;
  1727. var bottom=border.Bottom;
  1728. }
  1729. var x=left, y=top;
  1730. y=top+fontHeight/2;
  1731. for(var item of this.OverlayIndex)
  1732. {
  1733. var overlayItem=item[1];
  1734. var overlayID=item[0];
  1735. x=left;
  1736. if (!overlayItem.IsShowIndexTitle) continue;
  1737. if (overlayItem.Title && this.IsShowOverlayIndexName)
  1738. {
  1739. var textWidth=this.Canvas.measureText(overlayItem.Title).width+2;
  1740. if ((x+textWidth)<right)
  1741. {
  1742. if (this.OverlayIndexType.BGColor)
  1743. {
  1744. this.Canvas.fillStyle=this.OverlayIndexType.BGColor;
  1745. var rtBG={Left:x, Top:y-fontHeight/2, Width:textWidth, Height: fontHeight+lineSpace }; //保存下标题的坐标
  1746. this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
  1747. }
  1748. this.Canvas.fillStyle=this.TitleColor;
  1749. this.Canvas.fillText(overlayItem.Title,x,y,textWidth);
  1750. }
  1751. x+=textWidth;
  1752. }
  1753. for(var i=0; i<overlayItem.Data.length; ++i)
  1754. {
  1755. var item=overlayItem.Data[i];
  1756. var outText=this.GetTitleItem(item, false);
  1757. if (!outText) continue;
  1758. var valueText=outText.Text;
  1759. var aryText=outText.ArrayText;
  1760. if (aryText)
  1761. {
  1762. var text;
  1763. for(var k=0;k<aryText.length;++k)
  1764. {
  1765. var titleItem=aryText[k];
  1766. if (titleItem.Name) text=titleItem.Name+":"+titleItem.Text;
  1767. else text=titleItem.Text;
  1768. var textWidth=this.Canvas.measureText(text).width+this.ParamSpace;
  1769. if ((left+textWidth)>right) break;
  1770. this.Canvas.fillStyle=titleItem.Color;
  1771. this.Canvas.fillText(text,x,y,textWidth);
  1772. x+=textWidth;
  1773. }
  1774. }
  1775. else
  1776. {
  1777. var text=valueText;
  1778. if (item.Name)
  1779. {
  1780. var dyTitle=this.GetDynamicOutName(item.Name);
  1781. if (dyTitle) text=dyTitle+ ":" + valueText;
  1782. else text = item.Name + ":" + valueText;
  1783. }
  1784. textWidth = this.Canvas.measureText(text).width + this.ParamSpace; //后空2个像素
  1785. if (textWidth+left>right) break; //画不下了就不画了
  1786. if (this.OverlayIndexType.BGColor)
  1787. {
  1788. this.Canvas.fillStyle=this.OverlayIndexType.BGColor;
  1789. var rtBG={Left:x, Top:y-fontHeight/2, Width:textWidth, Height: fontHeight+lineSpace }; //保存下标题的坐标
  1790. this.Canvas.fillRect(rtBG.Left,rtBG.Top,rtBG.Width,rtBG.Height);
  1791. }
  1792. this.Canvas.fillStyle = item.Color;
  1793. this.Canvas.fillText(text, x, y, textWidth);
  1794. x += textWidth;
  1795. }
  1796. }
  1797. y+=fontHeight+lineSpace;
  1798. }
  1799. }
  1800. }
  1801. //导出统一使用JSCommon命名空间名
  1802. export
  1803. {
  1804. IChartTitlePainting,
  1805. DynamicKLineTitlePainting,
  1806. DynamicMinuteTitlePainting,
  1807. DynamicChartTitlePainting,
  1808. DynamicTitleData,
  1809. STRING_FORMAT_TYPE,
  1810. };
  1811. /*
  1812. module.exports =
  1813. {
  1814. JSCommonChartTitle:
  1815. {
  1816. IChartTitlePainting: IChartTitlePainting,
  1817. DynamicKLineTitlePainting: DynamicKLineTitlePainting,
  1818. DynamicMinuteTitlePainting: DynamicMinuteTitlePainting,
  1819. DynamicChartTitlePainting: DynamicChartTitlePainting,
  1820. DynamicTitleData: DynamicTitleData,
  1821. STRING_FORMAT_TYPE: STRING_FORMAT_TYPE,
  1822. },
  1823. //单个类导出
  1824. JSCommonChartTitle_IChartTitlePainting: IChartTitlePainting,
  1825. JSCommonChartTitle_DynamicKLineTitlePainting: DynamicKLineTitlePainting,
  1826. JSCommonChartTitle_DynamicMinuteTitlePainting: DynamicMinuteTitlePainting,
  1827. JSCommonChartTitle_DynamicChartTitlePainting: DynamicChartTitlePainting,
  1828. JSCommonChartTitle_DynamicTitleData: DynamicTitleData,
  1829. JSCommonChartTitle_STRING_FORMAT_TYPE: STRING_FORMAT_TYPE,
  1830. };
  1831. */