/* copyright (c) 2018 jones http://www.apache.org/licenses/LICENSE-2.0 开源项目 https://github.com/jones2000/HQChart jones_2000@163.com 封装图形控件 (微信小程序版本) */ //日志 import { JSConsole } from "./umychart.console.wechat.js" //行情数据结构体 及涉及到的行情算法(复权,周期等) import { JSCommon_ChartData as ChartData, JSCommon_HistoryData as HistoryData, JSCommon_SingleData as SingleData, JSCommon_MinuteData as MinuteData, JSCommon_CUSTOM_DAY_PERIOD_START as CUSTOM_DAY_PERIOD_START, JSCommon_CUSTOM_DAY_PERIOD_END as CUSTOM_DAY_PERIOD_END, JSCommon_CUSTOM_MINUTE_PERIOD_START as CUSTOM_MINUTE_PERIOD_START, JSCommon_CUSTOM_MINUTE_PERIOD_END as CUSTOM_MINUTE_PERIOD_END, JSCommon_CUSTOM_SECOND_PERIOD_START as CUSTOM_SECOND_PERIOD_START, JSCommon_CUSTOM_SECOND_PERIOD_END as CUSTOM_SECOND_PERIOD_END, JSCommon_Rect as Rect, JSCommon_DataPlus as DataPlus, JSCommon_JSCHART_EVENT_ID as JSCHART_EVENT_ID, JSCommon_PhoneDBClick as PhoneDBClick, } from "./umychart.data.wechat.js"; import { JSCommon_JSKLineInfoMap as JSKLineInfoMap, JSCommon_KLINE_INFO_TYPE as KLINE_INFO_TYPE, JSCommon_JSMinuteInfoMap as JSMinuteInfoMap, } from "./umychart.klineinfo.wechat.js"; import { JSCommonCoordinateData as JSCommonCoordinateData, JSCommonCoordinateData_MARKET_SUFFIX_NAME as MARKET_SUFFIX_NAME , JSCommonCoordinateData_Global_FuturesTimeData as g_FuturesTimeData, JSCommonCoordinateData_Global_NYMEXTimeData as g_NYMEXTimeData, JSCommonCoordinateData_Global_COMEXTimeData as g_COMEXTimeData, JSCommonCoordinateData_Global_NYBOTTimeData as g_NYBOTTimeData, JSCommonCoordinateData_Global_LMETimeData as g_LMETimeData, JSCommonCoordinateData_Global_CBOTTimeData as g_CBOTTimeData, } from "./umychart.coordinatedata.wechat.js"; import { JSCommonComplier } from "./umychart.complier.wechat.js"; //通达信编译器 import { JSCommonIndexScript } from "./umychart.index.data.wechat.js"; //系统指标定义 import { JSCommon_HQIndexFormula as HQIndexFormula } from "./umychart.hqIndexformula.wechat.js"; //通达信编译器 //图形库 import { JSCommonChartPaint_IChartPainting as IChartPainting, JSCommonChartPaint_ChartSingleText as ChartSingleText, JSCommonChartPaint_ChartKLine as ChartKLine, JSCommonChartPaint_ChartLine as ChartLine, JSCommonChartPaint_ChartSubLine as ChartSubLine, JSCommonChartPaint_ChartPointDot as ChartPointDot, JSCommonChartPaint_ChartStick as ChartStick, JSCommonChartPaint_ChartLineStick as ChartLineStick, JSCommonChartPaint_ChartStickLine as ChartStickLine, JSCommonChartPaint_ChartOverlayKLine as ChartOverlayKLine, JSCommonChartPaint_ChartMinuteInfo as ChartMinuteInfo, JSCommonChartPaint_ChartRectangle as ChartRectangle, JSCommonChartPaint_ChartMultiText as ChartMultiText, JSCommonChartPaint_ChartMultiLine as ChartMultiLine, JSCommonChartPaint_ChartMultiBar as ChartMultiBar, JSCommonChartPaint_ChartPie as ChartPie, JSCommonChartPaint_ChartCircle as ChartCircle, JSCommonChartPaint_ChartChinaMap as ChartChinaMap, JSCommonChartPaint_ChartRadar as ChartRadar, JSCommonChartPaint_ChartCorssCursor as ChartCorssCursor, JSCommonChartPaint_ChartBuySell as ChartBuySell, JSCommonChartPaint_ChartMACD as ChartMACD, JSCommonChartPaint_ChartSplashPaint as ChartSplashPaint, JSCommonChartPaint_ChartBackground as ChartBackground, JSCommonChartPaint_ChartMinuteVolumBar as ChartMinuteVolumBar, JSCommonChartPaint_ChartMultiHtmlDom as ChartMultiHtmlDom, JSCommonChartPaint_ChartLock as ChartLock, JSCommonChartPaint_ChartVolStick as ChartVolStick, JSCommonChartPaint_ChartBand as ChartBand, JSCommonChartPaint_DepthChartCorssCursor as DepthChartCorssCursor, JSCommonChartPaint_ChartOrderbookDepth as ChartOrderbookDepth, JSCommonChartPaint_ChartMinutePriceLine as ChartMinutePriceLine, JSCommonChartPaint_ChartText as ChartText , JSCommonChartPaint_ChartStraightArea as ChartStraightArea, } from "./umychart.chartpaint.wechat.js"; //扩展画法图形库 import { JSCommonExtendChartPaint_IExtendChartPainting as IExtendChartPainting, JSCommonExtendChartPaint_KLineTooltipPaint as KLineTooltipPaint, JSCommonExtendChartPaint_BarragePaint as BarragePaint, JSCommonExtendChartPaint_MinuteTooltipPaint as MinuteTooltipPaint, JSCommonExtendChartPaint_BackgroundPaint as BackgroundPaint, } from "./umychart.extendchart.wechat.js"; import { JSCommonIndex_IndexInfo as IndexInfo, JSCommonIndex_BaseIndex as BaseIndex, JSCommonIndex_ScriptIndex as ScriptIndex, } from './umychart.index.wechat.js' import{ JSCommonResource_Global_JSChartResource as g_JSChartResource, JSCommonResource_JSCHART_LANGUAGE_ID as JSCHART_LANGUAGE_ID, JSCommonResource_Global_JSChartLocalization as g_JSChartLocalization, } from './umychart.resource.wechat.js' import { JSCommonUniApp } from './umychart.uniapp.canvas.helper.js' import { JSCommonSplit_CoordinateInfo as CoordinateInfo, JSCommonSplit_IFrameSplitOperator as IFrameSplitOperator, JSCommonSplit_FrameSplitKLinePriceY as FrameSplitKLinePriceY, JSCommonSplit_FrameSplitY as FrameSplitY, JSCommonSplit_FrameSplitKLineX as FrameSplitKLineX, JSCommonSplit_FrameSplitMinutePriceY as FrameSplitMinutePriceY, JSCommonSplit_FrameSplitMinuteX as FrameSplitMinuteX, JSCommonSplit_FrameSplitXData as FrameSplitXData, JSCommonSplit_SplitData as SplitData, JSCommonSplit_PriceSplitData as PriceSplitData, JSCommonSplit_FrameSplitXDepth as FrameSplitXDepth, JSCommonFormat_IChangeStringFormat as IChangeStringFormat, JSCommonFormat_HQPriceStringFormat as HQPriceStringFormat, JSCommonFormat_HQDateStringFormat as HQDateStringFormat, JSCommonFormat_HQMinuteTimeStringFormat as HQMinuteTimeStringFormat, JSCommonFormat_Global_DataFormat as g_DivTooltipDataForamt, } from './umychart.framesplit.wechat.js' import { JSCommonChartTitle_IChartTitlePainting as IChartTitlePainting, JSCommonChartTitle_DynamicKLineTitlePainting as DynamicKLineTitlePainting, JSCommonChartTitle_DynamicMinuteTitlePainting as DynamicMinuteTitlePainting, JSCommonChartTitle_DynamicChartTitlePainting as DynamicChartTitlePainting, JSCommonChartTitle_DynamicTitleData as DynamicTitleData, JSCommonChartTitle_STRING_FORMAT_TYPE as STRING_FORMAT_TYPE, } from './umychart.charttitle.wechat.js' function JSCanvasElement() { this.Height; this.Width; this.ID; this.WebGLCanvas; this.IsUniApp=false; this.CanvasNode=null; this.ComponentObject=null; //在自定义组件下,当前组件实例的this,表示在这个自定义组件下查找拥有 canvas-id 的 canvas ,如果省略则不在任何自定义组件内查找 //获取画布 this.GetContext = function () { var canvas; if (this.CanvasNode && this.CanvasNode.node) { const width = this.CanvasNode.width; const height = this.CanvasNode.height; var node = this.CanvasNode.node; node._height = height; node._width = width; JSConsole.Chart.Log("[JSCanvasElement::GetContext] create by getContext('2d')"); canvas = node.getContext('2d'); const dpr = wx.getSystemInfoSync().pixelRatio; node.width = width * dpr; node.height = height * dpr; canvas.restore(); canvas.save(); canvas.scale(dpr, dpr); canvas.draw = (bDraw, callback) => { if (callback) callback(); }; canvas.DomNode = node; } else { if (this.ComponentObject) //小程序自定义组件 canvas=wx.createCanvasContext(this.ID,this.ComponentObject); else canvas=wx.createCanvasContext(this.ID); } if (this.IsUniApp) { JSConsole.Chart.Log('[JSCanvasElement::GetContext] measureText() => JSUniAppCanvasHelper.MeasureText()'); canvas.measureText = function (text) //uniapp 计算宽度需要自己计算 { var width = JSCommonUniApp.JSUniAppCanvasHelper.MeasureText(text, canvas); return { width: width }; } canvas.fillText_backup=canvas.fillText; //uniapp fillText 填了最大长度就会失真, 所以去掉 canvas.fillText=function(text,x,y,maxWidth) { canvas.fillText_backup(text,x,y); } } return canvas; } this.GetWebGLCanvas=function(id) { var self=this; const query = wx.createSelectorQuery(); query.select(id).node().exec((res) => { JSConsole.Chart.Log('[JSCanvasElement::GetWebGLCanvas] res ', res) self.WebGLCanvas = res[0].node; }) } } function JSChart(element) { this.JSChartContainer; //画图控件 this.CanvasElement = element; this.AddEventCallback = function (obj) //事件回调 {event:事件id, callback:回调函数} { if (this.JSChartContainer && typeof (this.JSChartContainer.AddEventCallback) == 'function') { JSConsole.Chart.Log('[JSChart:AddEventCallback] ', obj); this.JSChartContainer.AddEventCallback(obj); } } this.OnSize = function (option) { if (option) { if (IFrameSplitOperator.IsNumber(option.Width)) this.CanvasElement.Width=option.Width; if (IFrameSplitOperator.IsNumber(option.Height)) this.CanvasElement.Height=option.Height; } if (option && option.Redraw==false) return; if (this.JSChartContainer) { if (option && option.Type==1 && this.JSChartContainer.OnSize) { this.JSChartContainer.OnSize(); } else { if (this.JSChartContainer.Frame) this.JSChartContainer.Frame.SetSizeChage(true); this.JSChartContainer.Draw(); } } } //历史K线图 this.CreateKLineChartContainer = function (option) { var chart = null; if (option.Type === "历史K线图横屏") chart = new KLineChartHScreenContainer(this.CanvasElement); else chart = new KLineChartContainer(this.CanvasElement); if (option.NetworkFilter) chart.NetworkFilter = option.NetworkFilter; if (option.KLine) //k线图的属性设置 { if (option.KLine.DragMode >= 0) chart.DragMode = option.KLine.DragMode; if (option.KLine.Right >= 0) chart.Right = option.KLine.Right; if (option.KLine.Period >= 0) chart.Period = option.KLine.Period; if (option.KLine.MaxReqeustDataCount > 0) chart.MaxReqeustDataCount = option.KLine.MaxReqeustDataCount; if (option.KLine.Info && option.KLine.Info.length > 0) chart.SetKLineInfo(option.KLine.Info, false); if (option.KLine.Policy && option.KLine.Policy.length > 0) chart.SetPolicyInfo(option.KLine.Policy, false); if (option.KLine.KLineDoubleClick == false) chart.MinuteDialog = this.MinuteDialog = null; if (option.KLine.MaxRequestMinuteDayCount > 0) chart.MaxRequestMinuteDayCount = option.KLine.MaxRequestMinuteDayCount; if (option.KLine.DrawType) chart.KLineDrawType = option.KLine.DrawType; if (option.KLine.RightSpaceCount >= 0) chart.RightSpaceCount = option.KLine.RightSpaceCount; if (option.KLine.DataWidth>=1) chart.KLineSize={ DataWidth:option.KLine.DataWidth }; } if (IFrameSplitOperator.IsString(option.SplashTitle)) chart.LoadDataSplashTitle = option.SplashTitle; //设置提示信息内容 if (IFrameSplitOperator.IsBool(option.EnableZoomIndexWindow)) chart.EnableZoomIndexWindow=option.EnableZoomIndexWindow; //双击缩放附图 if (!option.Windows || option.Windows.length <= 0) return null; if (option.Language) { if (option.Language === 'CN') chart.LanguageID = JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; else if (option.Language === 'EN') chart.LanguageID = JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID; } if (option.SourceDatatLimit) chart.SetSourceDatatLimit(option.SourceDatatLimit); if (option.EnableZoomUpDown) chart.EnableZoomUpDown=option.EnableZoomUpDown; if (option.ZoomStepPixel>0) chart.ZoomStepPixel=option.ZoomStepPixel; if (IFrameSplitOperator.IsNumber(option.DrawMoveWaitTime)) chart.DrawMoveWaitTime=option.DrawMoveWaitTime; //创建子窗口 chart.Create(option.Windows.length); if (option.Border) { var item=option.Border; if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left = option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right = option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top = option.Border.Top; if (!isNaN(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom = option.Border.Bottom; if (item.AutoLeft) chart.Frame.AutoLeftBorder=item.AutoLeft; if (item.AutoRight) chart.Frame.AutoRightBorder=item.AutoRight; } if (option.KLine) { if (option.KLine.PageSize > 0) { let maxPageSize = chart.GetMaxPageSize(); if (maxPageSize < option.KLine.PageSize) chart.PageSize = maxPageSize; else chart.PageSize = option.KLine.PageSize; } if (option.KLine.InfoDrawType) chart.ChartPaint[0].InfoDrawType = option.KLine.InfoDrawType; } if (option.DragDownload) { if (option.DragDownload.Day && option.DragDownload.Day.Enable == true) chart.DragDownload.Day.Enable = true; if (option.DragDownload.Minute && option.DragDownload.Minute.Enable == true) chart.DragDownload.Minute.Enable = true; } if (option.IsApiPeriod == true) chart.IsApiPeriod = option.IsApiPeriod; if (option.CorssCursorTouchEnd == true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd; if (option.IsClickShowCorssCursor == true) chart.IsClickShowCorssCursor = option.IsClickShowCorssCursor; if (option.IsFullDraw == true) chart.IsFullDraw = option.IsFullDraw; if (option.CorssCursorInfo) { var item=option.CorssCursorInfo; if (!isNaN(option.CorssCursorInfo.Left)) chart.ChartCorssCursor.ShowTextMode.Left = option.CorssCursorInfo.Left; if (!isNaN(option.CorssCursorInfo.Right)) chart.ChartCorssCursor.ShowTextMode.Right = option.CorssCursorInfo.Right; if (!isNaN(option.CorssCursorInfo.Bottom)) chart.ChartCorssCursor.ShowTextMode.Bottom = option.CorssCursorInfo.Bottom; if (option.CorssCursorInfo.IsShowCorss === false) chart.ChartCorssCursor.IsShowCorss = option.CorssCursorInfo.IsShowCorss; if (option.CorssCursorInfo.IsShowClose == true) chart.ChartCorssCursor.IsShowClose = option.CorssCursorInfo.IsShowClose; //Y轴显示收盘价 if (IFrameSplitOperator.IsNumber(option.CorssCursorInfo.HPenType)) chart.ChartCorssCursor.HPenType = option.CorssCursorInfo.HPenType; if (option.CorssCursorInfo.VPenType > 0) chart.ChartCorssCursor.VPenType = option.CorssCursorInfo.VPenType; if (IFrameSplitOperator.IsNumber(item.DateFormatType)) chart.ChartCorssCursor.StringFormatX.DateFormatType=item.DateFormatType; } if (typeof (option.UpdateUICallback) == 'function') //数据到达回调 chart.UpdateUICallback = option.UpdateUICallback; if (option.Frame) { for (var i in option.Frame) { var item = option.Frame[i]; if (!chart.Frame.SubFrame[i]) continue; if (item.SplitCount) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount = item.SplitCount; if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat = item.StringFormat; if (!isNaN(item.Height)) chart.Frame.SubFrame[i].Height = item.Height; if (item.IsShowBorder == false) chart.Frame.SubFrame[i].Frame.IsShowBorder = item.IsShowBorder; if (item.IsShowXLine == false) chart.Frame.SubFrame[i].Frame.IsShowXLine = item.IsShowXLine; if (item.IsShowYLine==false) chart.Frame.SubFrame[i].Frame.IsShowYLine=item.IsShowYLine; if (item.XMessageAlign == 'bottom') chart.Frame.SubFrame[i].Frame.XMessageAlign = item.XMessageAlign; if (item.IsShowTitle == false) chart.Frame.SubFrame[i].Frame.IsShowTitle = false; if (IFrameSplitOperator.IsBool(item.IsShowIndexTitle)) chart.Frame.SubFrame[i].Frame.IsShowTitle=item.IsShowIndexTitle; if (item.UpdateTitleUICallback && chart.Frame.SubFrame[i].Frame.TitlePaint) chart.Frame.SubFrame[i].Frame.TitlePaint.UpdateUICallback = item.UpdateTitleUICallback; if (item.IsShowLeftText === false || item.IsShowLeftText === true) chart.Frame.SubFrame[i].Frame.IsShowYText[0] = item.IsShowLeftText; //显示左边刻度 if (item.IsShowRightText === false || item.IsShowRightText === true) chart.Frame.SubFrame[i].Frame.IsShowYText[1] = item.IsShowRightText; //显示右边刻度 if (item.TopSpace >= 0) chart.Frame.SubFrame[i].Frame.ChartBorder.TopSpace = item.TopSpace; if (item.BottomSpace >= 0) chart.Frame.SubFrame[i].Frame.ChartBorder.BottomSpace = item.BottomSpace; if (item.Custom) chart.Frame.SubFrame[i].Frame.YSplitOperator.Custom = item.Custom; if (IFrameSplitOperator.IsNumber(item.SplitType)) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitType = item.SplitType; if (IFrameSplitOperator.IsNumber(item.FloatPrecision)) chart.Frame.SubFrame[i].Frame.YSplitOperator.FloatPrecision = item.FloatPrecision; //强制指定小数位数(主图有效) if (IFrameSplitOperator.IsNumber(item.BorderLine)) chart.Frame.SubFrame[i].Frame.BorderLine=item.BorderLine; if (IFrameSplitOperator.IsNumber(item.YTextBaseline)) chart.Frame.SubFrame[i].Frame.YTextBaseline=item.YTextBaseline; } } if (option.KLine) { if (option.KLine.ShowKLine == false) chart.ChartPaint[0].IsShow = false; if (option.KLine.IsShowMaxMinPrice == false) chart.ChartPaint[0].IsShowMaxMinPrice = false; } if (option.KLineTitle) { if (option.KLineTitle.IsShowName == false) chart.TitlePaint[0].IsShowName = false; if (option.KLineTitle.IsShowSettingInfo == false) chart.TitlePaint[0].IsShowSettingInfo = false; if (option.KLineTitle.IsShow == false) chart.TitlePaint[0].IsShow = false; if (option.KLineTitle.UpdateUICallback) chart.TitlePaint[0].UpdateUICallback = option.KLineTitle.UpdateUICallback if (option.KLineTitle.LineCount > 1) chart.TitlePaint[0].LineCount = option.KLineTitle.LineCount; } //叠加股票 只支持叠加1个股票 for (var i in option.Overlay) { var item = option.Overlay[i]; if (item.Symbol) { chart.OverlayChartPaint[0].Symbol = item.Symbol; if (item.Color) chart.OverlayChartPaint[0].Color=item.Color; chart.OverlayChartPaint[0].SetOption(item); break; } } if (option.ExtendChart) //创建扩展画法 { for (var i in option.ExtendChart) { var item = option.ExtendChart[i]; chart.CreateExtendChart(item.Name, item); } } let scriptData = new JSCommonIndexScript.JSIndexScript(); //系统指标 if (option.ColorIndex) //五彩K线 { var item = option.ColorIndex; let indexInfo = scriptData.Get(item.Index); if (indexInfo) chart.ColorIndex = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args, indexInfo); //脚本执行 } if (option.TradeIndex) //交易指标 { var item = option.TradeIndex; let indexInfo = scriptData.Get(item.Index); if (indexInfo) chart.TradeIndex = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args, indexInfo); //脚本执行 } for (var i in option.Windows) //创建子窗口的指标 { var item = option.Windows[i]; if (item.Script) { chart.WindowIndex[i] = new ScriptIndex(item.Name, item.Script, item.Args, item); //脚本执行 } else if (item.API) //使用API挂接指标数据 API:{ Name:指标名字, Script:指标脚本可以为空, Args:参数可以为空, Url:指标执行地址 } { var apiItem = item.API; chart.WindowIndex[i] = new APIScriptIndex(apiItem.Name, apiItem.Script, apiItem.Args, item); } else { var indexItem = JSIndexMap.Get(item.Index); //自定义指标 if (indexItem) { chart.WindowIndex[i] = indexItem.Create(); chart.CreateWindowIndex(i); } else //系统指标里查找 { let indexInfo = scriptData.Get(item.Index); if (!indexInfo) continue; if (item.Lock) indexInfo.Lock = item.Lock; indexInfo.ID = item.Index; var args = indexInfo.Args; if (item.Args) args = item.Args; chart.WindowIndex[i] = new ScriptIndex(indexInfo.Name, indexInfo.Script, args, indexInfo); //脚本执行 if (item.StringFormat > 0) chart.WindowIndex[i].StringFormat = item.StringFormat; if (item.FloatPrecision >= 0) chart.WindowIndex[i].FloatPrecision = item.FloatPrecision; } } if (item.Modify != null) chart.Frame.SubFrame[i].Frame.ModifyIndex = item.Modify; if (item.Change != null) chart.Frame.SubFrame[i].Frame.ChangeIndex = item.Change; if (item.IsDrawTitleBG==true) chart.Frame.SubFrame[i].Frame.IsDrawTitleBG=item.IsDrawTitleBG; if (typeof (item.UpdateUICallback) == 'function') chart.WindowIndex[i].UpdateUICallback = item.UpdateUICallback; if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight = item.TitleHeight; if (item.IsShowIndexName == false) chart.Frame.SubFrame[i].Frame.IsShowIndexName = false; if (item.IndexParamSpace >= 0) chart.Frame.SubFrame[i].Frame.IndexParamSpace = item.IndexParamSpace; } return chart; } //自定义指数历史K线图 this.CreateCustomKLineChartContainer = function (option) { var chart = new CustomKLineChartContainer(this.CanvasElement); if (option.KLine) //k线图的属性设置 { if (option.KLine.DragMode >= 0) chart.DragMode = option.KLine.DragMode; if (option.KLine.Right >= 0) chart.Right = option.KLine.Right; if (option.KLine.Period >= 0) chart.Period = option.KLine.Period; if (option.KLine.MaxReqeustDataCount > 0) chart.MaxReqeustDataCount = option.KLine.MaxReqeustDataCount; if (option.KLine.Info && option.KLine.Info.length > 0) chart.SetKLineInfo(option.KLine.Info, false); if (option.KLine.KLineDoubleClick == false) chart.MinuteDialog = this.MinuteDialog = null; if (option.KLine.PageSize > 0) chart.PageSize = option.KLine.PageSize; if (option.KLine.IsShowTooltip == false) chart.IsShowTooltip = false; } if (option.CustomStock) chart.CustomStock = option.CustomStock; if (option.QueryDate) chart.QueryDate = option.QueryDate; if (typeof (option.UpdateUICallback) == 'function') chart.UpdateUICallback = option.UpdateUICallback; if (!option.Windows || option.Windows.length <= 0) return null; //创建子窗口 chart.Create(option.Windows.length); if (option.Border) { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left = option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right = option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top = option.Border.Top; if (!isNaN(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom = option.Border.Bottom; } if (option.IsShowCorssCursorInfo == false) //取消显示十字光标刻度信息 { chart.ChartCorssCursor.IsShowText = option.IsShowCorssCursorInfo; } if (option.Frame) { for (var i in option.Frame) { var item = option.Frame[i]; if (item.SplitCount) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount = item.SplitCount; if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat = item.StringFormat; if (item.XMessageAlign == 'bottom') chart.Frame.SubFrame[i].Frame.XMessageAlign = item.XMessageAlign; } } if (option.KLineTitle) { if (option.KLineTitle.IsShowName == false) chart.TitlePaint[0].IsShowName = false; if (option.KLineTitle.IsShowSettingInfo == false) chart.TitlePaint[0].IsShowSettingInfo = false; } //创建子窗口的指标 let scriptData = new JSCommonIndexScript.JSIndexScript(); for (var i in option.Windows) { var item = option.Windows[i]; if (item.Script) { chart.WindowIndex[i] = new ScriptIndex(item.Name, item.Script, item.Args, item); //脚本执行 } else { var indexItem = JSIndexMap.Get(item.Index); if (indexItem) { chart.WindowIndex[i] = indexItem.Create(); chart.CreateWindowIndex(i); } else //系统指标里查找 { let indexInfo = scriptData.Get(item.Index); if (!indexInfo) continue; if (item.Lock) indexInfo.Lock = item.Lock; chart.WindowIndex[i] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args, indexInfo); //脚本执行 } } if (item.Modify != null) chart.Frame.SubFrame[i].Frame.ModifyIndex = item.Modify; if (item.Change != null) chart.Frame.SubFrame[i].Frame.ChangeIndex = item.Change; if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight = item.TitleHeight; } return chart; } //分钟走势图 this.CreateMinuteChartContainer = function (option) { var chart = null; if (option.Type === "分钟走势图横屏") chart = new MinuteChartHScreenContainer(this.CanvasElement); else chart = new MinuteChartContainer(this.CanvasElement); if (option.NetworkFilter) chart.NetworkFilter = option.NetworkFilter; var windowsCount = 2; if (option.Windows && option.Windows.length > 0) windowsCount += option.Windows.length; //指标窗口从第3个窗口开始 if (option.EnableScrollUpDown==true) chart.EnableScrollUpDown=option.EnableScrollUpDown; if (option.Info && option.Info.length > 0) chart.SetMinuteInfo(option.Info, false); if (IFrameSplitOperator.IsString(option.SplashTitle)) chart.LoadDataSplashTitle = option.SplashTitle; //设置提示信息内容 if (IFrameSplitOperator.IsBool(option.EnableZoomIndexWindow)) chart.EnableZoomIndexWindow=option.EnableZoomIndexWindow; //双击缩放附图 if (IFrameSplitOperator.IsNumber(option.DrawMoveWaitTime)) chart.DrawMoveWaitTime=option.DrawMoveWaitTime; if (option.Language) { if (option.Language === 'CN') chart.LanguageID = JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; else if (option.Language === 'EN') chart.LanguageID = JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID; } chart.Create(windowsCount); //创建子窗口 if (option.CorssCursorTouchEnd == true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd; if (option.IsFullDraw == true) chart.IsFullDraw = option.IsFullDraw; if (option.CorssCursorInfo) //十字光标设置 { if (!isNaN(option.CorssCursorInfo.Left)) chart.ChartCorssCursor.ShowTextMode.Left = option.CorssCursorInfo.Left; if (!isNaN(option.CorssCursorInfo.Right)) chart.ChartCorssCursor.ShowTextMode.Right = option.CorssCursorInfo.Right; if (!isNaN(option.CorssCursorInfo.Bottom)) chart.ChartCorssCursor.ShowTextMode.Bottom = option.CorssCursorInfo.Bottom; if (option.CorssCursorInfo.IsShowCorss === false) chart.ChartCorssCursor.IsShowCorss = option.CorssCursorInfo.IsShowCorss; if (IFrameSplitOperator.IsBool(option.CorssCursorInfo.IsFixXLastTime)) chart.ChartCorssCursor.IsFixXLastTime=option.CorssCursorInfo.IsFixXLastTime; } if (option.MinuteInfo) chart.CreateMinuteInfo(option.MinuteInfo); if (option.DayCount > 1) chart.DayCount = option.DayCount; if (option.Border) { var item=option.Border; if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left = option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right = option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top = option.Border.Top; if (!isNaN(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom = option.Border.Bottom; if (item.AutoLeft) chart.Frame.AutoLeftBorder=item.AutoLeft; if (item.AutoRight) chart.Frame.AutoRightBorder=item.AutoRight; } if (option.Frame) { for (var i in option.Frame) { var item = option.Frame[i]; if (!chart.Frame.SubFrame[i]) continue; if (item.SplitCount) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount = item.SplitCount; if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat = item.StringFormat; if (item.XMessageAlign == 'bottom') chart.Frame.SubFrame[i].Frame.XMessageAlign = item.XMessageAlign; if (item.IsShowLeftText === false || item.IsShowLeftText===true ) chart.Frame.SubFrame[i].Frame.IsShowYText[0] = item.IsShowLeftText; //显示左边刻度 if (item.IsShowRightText === false || item.IsShowRightText===true) chart.Frame.SubFrame[i].Frame.IsShowYText[1] = item.IsShowRightText; //显示右边刻度 if (item.Height >= 0) chart.Frame.SubFrame[i].Height = item.Height; if (item.Custom) chart.Frame.SubFrame[i].Frame.YSplitOperator.Custom = item.Custom; if (IFrameSplitOperator.IsNumber(item.BorderLine)) chart.Frame.SubFrame[i].Frame.BorderLine=item.BorderLine; if (IFrameSplitOperator.IsNumber(item.YTextBaseline)) chart.Frame.SubFrame[i].Frame.YTextBaseline=item.YTextBaseline; } chart.UpdateXShowText(); } if (option.MinuteTitle) { if (option.MinuteTitle.IsShowName == false) chart.TitlePaint[0].IsShowName = false; if (option.MinuteTitle.IsShow == false) chart.TitlePaint[0].IsShow = false; if (option.MinuteTitle.UpdateUICallback) chart.TitlePaint[0].UpdateUICallback = option.MinuteTitle.UpdateUICallback if (option.MinuteTitle.LineCount > 1) chart.TitlePaint[0].LineCount = option.MinuteTitle.LineCount; } if (typeof (option.UpdateUICallback) == 'function') //数据到达回调 chart.UpdateUICallback = option.UpdateUICallback; if (option.ExtendChart) //创建扩展画法 { for (var i in option.ExtendChart) { var item = option.ExtendChart[i]; chart.CreateExtendChart(item.Name, item); } } //叠加股票 只支持1只股票 for (var i in option.Overlay) { var item = option.Overlay[i]; if (item.Symbol) { chart.OverlayChartPaint[0].Symbol = item.Symbol; if (item.Color) chart.OverlayChartPaint[0].Color = item.Color; break; } } if (option.Overlay && option.Overlay.length) { chart.OverlayChartPaint[0].Symbol = option.Overlay[0].Symbol; } if (option.MinuteLine) { if (option.MinuteLine.IsDrawAreaPrice == false) chart.ChartPaint[0].IsDrawArea = false; if (option.MinuteLine.IsShowAveragePrice == false) { chart.ChartPaint[1].IsShow = false; chart.TitlePaint[0].IsShowAveragePrice=false; //标题栏均线也不显示 for(var i in chart.ExtendChartPaint) { var item=chart.ExtendChartPaint[i]; if (item.ClassName=="MinuteTooltipPaint") item.IsShowAveragePrice=false; } } if (option.MinuteLine.SplitType>0) chart.Frame.SubFrame[0].Frame.YSplitOperator.SplitType=option.MinuteLine.SplitType; } let scriptData = new JSCommonIndexScript.JSIndexScript(); for (var i in option.Windows) //分钟数据指标从第3个指标窗口设置 { var item = option.Windows[i]; if (item.Script) { chart.WindowIndex[2 + parseInt(i)] = new ScriptIndex(item.Name, item.Script, item.Args, item); //脚本执行 } else { var indexItem = JSIndexMap.Get(item.Index); if (indexItem) { chart.WindowIndex[2 + parseInt(i)] = indexItem.Create(); //创建子窗口的指标 chart.CreateWindowIndex(2 + parseInt(i)); } else { let indexInfo = scriptData.Get(item.Index); if (!indexInfo) continue; var args = indexInfo.Args; if (item.Args) args = item.Args; if (item.Lock) indexInfo.Lock = item.Lock; chart.WindowIndex[2 + parseInt(i)] = new ScriptIndex(indexInfo.Name, indexInfo.Script, args, indexInfo); //脚本执行 if (item.StringFormat > 0) chart.WindowIndex[2 + parseInt(i)].StringFormat = item.StringFormat; if (item.FloatPrecision >= 0) chart.WindowIndex[2 + parseInt(i)].FloatPrecision = item.FloatPrecision; } } if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[2 + parseInt(i)].Frame.ChartBorder.TitleHeight = item.TitleHeight; //指标标题高度 } return chart; } //历史分钟走势图 this.CreateHistoryMinuteChartContainer = function (option) { var chart = new HistoryMinuteChartContainer(this.CanvasElement); var windowsCount = 2; if (option.Windows && option.Windows.length > 0) windowsCount += option.Windows.length; //指标窗口从第3个窗口开始 chart.Create(windowsCount); //创建子窗口 if (option.IsShowCorssCursorInfo == false) //取消显示十字光标刻度信息 { chart.ChartCorssCursor.IsShowText = option.IsShowCorssCursorInfo; } if (option.Border) { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left = option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right = option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top = option.Border.Top; if (!isNaN(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom = option.Border.Bottom; } if (option.Frame) { for (var i in option.Frame) { var item = option.Frame[i]; if (item.SplitCount) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount = item.SplitCount; if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat = item.StringFormat; if (item.XMessageAlign == 'bottom') chart.Frame.SubFrame[i].Frame.XMessageAlign = item.XMessageAlign; } } let scriptData = new JSCommonIndexScript.JSIndexScript(); for (var i in option.Windows) //分钟数据指标从第3个指标窗口设置 { var item = option.Windows[i]; if (item.Script) { chart.WindowIndex[2 + parseInt(i)] = new ScriptIndex(item.Name, item.Script, item.Args, item); //脚本执行 } else { var indexItem = JSIndexMap.Get(item.Index); if (indexItem) { chart.WindowIndex[2 + parseInt(i)] = indexItem.Create(); //创建子窗口的指标 chart.CreateWindowIndex(2 + parseInt(i)); } else { let indexInfo = scriptData.Get(item.Index); if (!indexInfo) continue; if (item.Lock) indexInfo.Lock = item.Lock; chart.WindowIndex[2 + parseInt(i)] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args, indexInfo); //脚本执行 } } if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[2 + parseInt(i)].Frame.ChartBorder.TitleHeight = item.TitleHeight; } chart.TradeDate = 20181009; if (option.HistoryMinute) { if (option.HistoryMinute.TradeDate) chart.TradeDate = option.HistoryMinute.TradeDate; if (option.HistoryMinute.IsShowName != null) chart.TitlePaint[0].IsShowName = option.HistoryMinute.IsShowName; //动态标题是否显示股票名称 if (option.HistoryMinute.IsShowDate != null) chart.TitlePaint[0].IsShowDate = option.HistoryMinute.IsShowDate; //动态标题是否显示日期 } return chart; } this.CreateKLineTrainChartContainer = function (option) { var bHScreen = (option.Type == 'K线训练横屏' ? true : false); var chart = new KLineTrainChartContainer(this.CanvasElement, bHScreen); if (option.NetworkFilter) chart.NetworkFilter = option.NetworkFilter; if (option.IsApiPeriod == true) chart.IsApiPeriod = option.IsApiPeriod; if (option.KLine) //k线图的属性设置 { if (option.KLine.Right >= 0) chart.Right = option.KLine.Right; if (option.KLine.Period >= 0) chart.Period = option.KLine.Period; if (option.KLine.MaxReqeustDataCount > 0) chart.MaxReqeustDataCount = option.KLine.MaxReqeustDataCount; if (option.KLine.Info && option.KLine.Info.length > 0) chart.SetKLineInfo(option.KLine.Info, false); if (option.KLine.PageSize > 0) chart.PageSize = option.KLine.PageSize; if (option.KLine.IsShowTooltip == false) chart.IsShowTooltip = false; if (option.KLine.MaxRequestMinuteDayCount > 0) chart.MaxRequestMinuteDayCount = option.KLine.MaxRequestMinuteDayCount; if (option.KLine.DrawType) chart.KLineDrawType = option.KLine.DrawType; } if (option.Train) { if (option.Train.DataCount) chart.TrainDataCount = option.Train.DataCount; if (option.Train.Callback) chart.TrainCallback = option.Train.Callback; if (option.Train.StartDate) chart.TrainStartDate = option.Train.StartDate; } if (!option.Windows || option.Windows.length <= 0) return null; //创建子窗口 chart.Create(option.Windows.length); if (option.Border) { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left = option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right = option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top = option.Border.Top; if (!isNaN(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom = option.Border.Bottom; } if (option.ExtendChart) //创建扩展画法 { for (var i in option.ExtendChart) { var item = option.ExtendChart[i]; chart.CreateExtendChart(item.Name, item); } } if (option.IsShowCorssCursorInfo == false) chart.ChartCorssCursor.IsShowText = option.IsShowCorssCursorInfo;//取消显示十字光标刻度信息 if (option.CorssCursorTouchEnd == true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd; if (option.IsClickShowCorssCursor == true) chart.IsClickShowCorssCursor = option.IsClickShowCorssCursor; if (option.IsFullDraw == true) chart.IsFullDraw = option.IsFullDraw; if (option.CorssCursorInfo) { if (!isNaN(option.CorssCursorInfo.Left)) chart.ChartCorssCursor.ShowTextMode.Left = option.CorssCursorInfo.Left; if (!isNaN(option.CorssCursorInfo.Right)) chart.ChartCorssCursor.ShowTextMode.Right = option.CorssCursorInfo.Right; if (!isNaN(option.CorssCursorInfo.Bottom)) chart.ChartCorssCursor.ShowTextMode.Bottom = option.CorssCursorInfo.Bottom; if (option.CorssCursorInfo.IsShowCorss === false) chart.ChartCorssCursor.IsShowCorss = option.CorssCursorInfo.IsShowCorss; if (option.CorssCursorInfo.IsShowClose == true) chart.ChartCorssCursor.IsShowClose = option.CorssCursorInfo.IsShowClose; //Y轴显示收盘价 if (option.CorssCursorInfo.HPenType > 0) chart.ChartCorssCursor.HPenType = option.CorssCursorInfo.HPenType; if (option.CorssCursorInfo.VPenType > 0) chart.ChartCorssCursor.VPenType = option.CorssCursorInfo.VPenType; if (IFrameSplitOperator.IsBool(option.CorssCursorInfo.IsFixXLastTime)) chart.ChartCorssCursor.IsFixXLastTime=option.CorssCursorInfo.IsFixXLastTime; } if (option.Frame) { for (var i in option.Frame) { if (!chart.Frame.SubFrame[i]) continue; var item = option.Frame[i]; if (item.SplitCount) chart.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount = item.SplitCount; if (item.StringFormat) chart.Frame.SubFrame[i].Frame.YSplitOperator.StringFormat = item.StringFormat; if (item.Height>0) chart.Frame.SubFrame[i].Height = item.Height; if (item.IsShowLeftText === false || item.IsShowLeftText === true) chart.Frame.SubFrame[i].Frame.IsShowYText[0] = item.IsShowLeftText; //显示左边刻度 if (item.IsShowRightText === false || item.IsShowRightText === true) chart.Frame.SubFrame[i].Frame.IsShowYText[1] = item.IsShowRightText; //显示右边刻度 } } if (option.KLine) { if (option.KLine.ShowKLine == false) chart.ChartPaint[0].IsShow = false; if (option.KLine.IsShowMaxMinPrice == false) chart.ChartPaint[0].IsShowMaxMinPrice = false; } //股票名称 日期 周期都不显示 chart.TitlePaint[0].IsShowName = false; chart.TitlePaint[0].IsShowSettingInfo = false; chart.TitlePaint[0].IsShowDateTime = false; //创建子窗口的指标 let scriptData = new JSCommonIndexScript.JSIndexScript(); for (var i in option.Windows) { var item = option.Windows[i]; if (item.Script) { chart.WindowIndex[i] = new ScriptIndex(item.Name, item.Script, item.Args, item); //脚本执行 } else { let indexItem = JSIndexMap.Get(item.Index); if (indexItem) { chart.WindowIndex[i] = indexItem.Create(); chart.CreateWindowIndex(i); } else { let indexInfo = scriptData.Get(item.Index); if (!indexInfo) continue; if (item.Lock) indexInfo.Lock = item.Lock; chart.WindowIndex[i] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args, indexInfo); //脚本执行 } } if (item.Modify != null) chart.Frame.SubFrame[i].Frame.ModifyIndex = item.Modify; if (item.Change != null) chart.Frame.SubFrame[i].Frame.ChangeIndex = item.Change; if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight = item.TitleHeight; } return chart; } //深度图 this.CreateDepthChartContainer=function(option) { var chart=null; chart=new DepthChartContainer(this.CanvasElement); if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter; if (option.EnableScrollUpDown==true) chart.EnableScrollUpDown=option.EnableScrollUpDown; if (IFrameSplitOperator.IsPlusNumber(option.MaxVolRate)) chart.MaxVolRate=option.MaxVolRate; if (option.ZoomStepPixel>0) chart.ZoomStepPixel=option.ZoomStepPixel; chart.Create(option.Listener); if (option.Border) { if (IFrameSplitOperator.IsNumber(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left; else option.Border.Left=chart.Frame.ChartBorder.Left; if (IFrameSplitOperator.IsNumber(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right; else option.Border.Right=chart.Frame.ChartBorder.Right; if (IFrameSplitOperator.IsNumber(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top; else option.Border.Top=chart.Frame.ChartBorder.Top; if (IFrameSplitOperator.IsNumber(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom=option.Border.Bottom; else option.Border.Bottom=chart.Frame.ChartBorder.Bottom; } if (option.IsFullDraw == true) chart.IsFullDraw = option.IsFullDraw; if (option.CorssCursorTouchEnd===true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd; if (option.CorssCursorInfo) { var item=option.CorssCursorInfo; if (IFrameSplitOperator.IsNumber(item.HPenType)) chart.ChartCorssCursor.HPenType=item.HPenType; if (IFrameSplitOperator.IsNumber(item.VPenType)) chart.ChartCorssCursor.VPenType=item.VPenType; if (IFrameSplitOperator.IsBool(item.IsShowTooltip)) chart.ChartCorssCursor.IsShowTooltip=item.IsShowTooltip; } if (option.Frame) { var item=option.Frame if (item.SplitCount) chart.Frame.YSplitOperator.SplitCount=item.SplitCount; if (IFrameSplitOperator.IsNumber(item.SplitType)) chart.Frame.YSplitOperator.SplitType=item.SplitType; if (IFrameSplitOperator.IsNumber(item.Height)) chart.Frame.Height = item.Height; if (IFrameSplitOperator.IsNumber(item.LineType)) chart.Frame.YSplitOperator.LineType=item.LineType; if (Array.isArray(item.IgnoreYValue)) chart.Frame.YSplitOperator.IgnoreYValue=item.IgnoreYValue; if (item.IsShowLeftText===false || item.IsShowLeftText===true) { chart.Frame.IsShowYText[0]=item.IsShowLeftText; chart.Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText; //显示左边刻度 } if (item.IsShowRightText===false || item.IsShowRightText===true) { chart.Frame.IsShowYText[1]=item.IsShowRightText; chart.Frame.YSplitOperator.IsShowRightText=item.IsShowRightText; //显示右边刻度 } if (item.IsShowXLine==false) chart.Frame.IsShowXLine=item.IsShowXLine; if (item.IsShowYLine==false) chart.Frame.IsShowYLine=item.IsShowYLine; } return chart; } //根据option内容绘制图形 this.SetOption = function (option) { JSConsole.Chart.Log('[JSChart::SetOption]', option) var chart = null; switch (option.Type) { case "历史K线图": case '历史K线图横屏': chart = this.CreateKLineChartContainer(option); break; case "自定义指数历史K线图": chart = this.CreateCustomKLineChartContainer(option); break; case "分钟走势图": case "分钟走势图横屏": chart = this.CreateMinuteChartContainer(option); break; case "历史分钟走势图": chart = this.CreateHistoryMinuteChartContainer(option); break; case 'K线训练': case 'K线训练横屏': chart = this.CreateKLineTrainChartContainer(option); break; case "深度图": chart=this.CreateDepthChartContainer(option); break; case "简单图形": return this.CreateSimpleChart(option); case '雷达图': case "饼图": return this.CreatePieChart(option); case '地图': return this.CreateMapChart(option); default: return false; } if (!chart) return false; if (option.OnCreatedCallback) option.OnCreatedCallback(chart); //是否自动更新 if (option.IsAutoUpdate == true || option.IsAutoUpate == true) chart.IsAutoUpdate = true; if (option.AutoUpdateFrequency > 0) chart.AutoUpdateFrequency = option.AutoUpdateFrequency; //注册事件 for(var i in option.EventCallback) { var item=option.EventCallback[i]; chart.AddEventCallback(item); } //设置股票代码 if (!option.Symbol) return false; this.JSChartContainer = chart; chart.Draw(); chart.ChangeSymbol(option.Symbol); this.JSChartContainer.Draw(); if (!IFrameSplitOperator.IsBool(option.CheckLatestVerion) || !(option.CheckLatestVerion==false)) { if (chart && this.CanvasElement.IsUniApp && typeof(chart.GetLatestVersion)=='function') chart.GetLatestVersion(); } } //切换股票代码接口 this.ChangeSymbol = function (symbol) { if (this.JSChartContainer) this.JSChartContainer.ChangeSymbol(symbol); } //K线切换指标 this.ChangeIndex = function (windowIndex, indexName, option) { if (this.JSChartContainer && typeof (this.JSChartContainer.ChangeIndex) == 'function') this.JSChartContainer.ChangeIndex(windowIndex, indexName, option); } //切换K线指标 this.ChangeScriptIndex = function (windowIndex, indexData) { if (this.JSChartContainer && typeof (this.JSChartContainer.ChangeScriptIndex) == 'function') this.JSChartContainer.ChangeScriptIndex(windowIndex, indexData); } //获取当前显示的指标信息 this.GetIndexInfo = function () { if (this.JSChartContainer && typeof (this.JSChartContainer.GetIndexInfo) == 'function') return this.JSChartContainer.GetIndexInfo(); else return []; } //K线周期切换 this.ChangePeriod = function (period, option) { if (this.JSChartContainer && typeof (this.JSChartContainer.ChangePeriod) == 'function') this.JSChartContainer.ChangePeriod(period, option); } //切换系统指示 this.ChangeInstructionIndex = function (indexName) { if (this.JSChartContainer && typeof (this.JSChartContainer.ChangeInstructionIndex) == 'function') this.JSChartContainer.ChangeInstructionIndex(indexName); } //切换自定义指示 this.ChangeInstructionScriptIndex = function (indexData) { if (this.JSChartContainer && typeof (this.JSChartContainer.ChangeInstructionIndex) == 'function') this.JSChartContainer.ChangeInstructionScriptIndex(indexData); } //增加一个指标窗口 this.AddIndexWindow=function(indexName,option) { if (this.JSChartContainer && typeof(this.JSChartContainer.AddIndexWindow)=='function') this.JSChartContainer.AddIndexWindow(indexName,option); } //删除一个指标窗口 this.RemoveIndexWindow=function(id) { if (this.JSChartContainer && typeof(this.JSChartContainer.RemoveIndexWindow)=='function') this.JSChartContainer.RemoveIndexWindow(id); } //取消指示 this.CancelInstructionIndex = function () { if (this.JSChartContainer && typeof (this.JSChartContainer.CancelInstructionIndex) == 'function') this.JSChartContainer.CancelInstructionIndex(); } //切换指标模板 this.ChangeIndexTemplate = function (option) { if (this.JSChartContainer && typeof (this.JSChartContainer.ChangeIndexTemplate) == 'function') { JSConsole.Chart.Log('[JSChart:ChangeIndexTemplate] ', option); this.JSChartContainer.ChangeIndexTemplate(option); } } //K线复权切换 this.ChangeRight = function (right) { if (this.JSChartContainer && typeof (this.JSChartContainer.ChangeRight) == 'function') this.JSChartContainer.ChangeRight(right); } //K线切换类型 0=实心K线 1=收盘价线 2=美国线 3=空心K线 this.ChangeKLineDrawType = function (drawType) { if (this.JSChartContainer && typeof (this.JSChartContainer.ChangeKLineDrawType) == 'function') this.JSChartContainer.ChangeKLineDrawType(drawType); } //切换数据类 this.ChangMainDataControl = function (dataControl) { if (this.JSChartContainer && typeof (this.JSChartContainer.SetMainDataConotrl) == 'function') this.JSChartContainer.SetMainDataConotrl(dataControl); } //叠加股票 this.OverlaySymbol = function (symbol,option) { if (this.JSChartContainer && typeof (this.JSChartContainer.OverlaySymbol) == 'function') this.JSChartContainer.OverlaySymbol(symbol, option); } //设置强制横屏 this.ForceLandscape = function (bForceLandscape) { if (this.JSChartContainer) { JSConsole.Chart.Log("[JSChart::ForceLandscape] bForceLandscape=" + bForceLandscape); this.JSChartContainer.IsForceLandscape = bForceLandscape; } } //锁|解锁指标 this.LockIndex = function (lockData) { if (this.JSChartContainer && typeof (this.JSChartContainer.LockIndex) == 'function') { JSConsole.Chart.Log('[JSChart:LockIndex] lockData', lockData); this.JSChartContainer.LockIndex(lockData); } } //历史分钟数据 更改日期 this.ChangeTradeDate = function (tradeDate) { if (this.JSChartContainer && typeof (this.JSChartContainer.ChangeTradeDate) == 'function') { JSConsole.Chart.Log('[JSChart:ChangeTradeDate] date', tradeDate); this.JSChartContainer.ChangeTradeDate(tradeDate); } } //多日走势图 this.ChangeDayCount = function (count) { if (this.JSChartContainer && typeof (this.JSChartContainer.ChangeDayCount) == 'function') { JSConsole.Chart.Log('[JSChart:ChangeDayCount] count', count); this.JSChartContainer.ChangeDayCount(count); } } this.StopAutoUpdate = function () { if (this.JSChartContainer && typeof (this.JSChartContainer.StopAutoUpdate) == 'function') { JSConsole.Chart.Log("[JSChart::StopAutoUpdate] Stop."); this.JSChartContainer.StopAutoUpdate(); } } this.StopAutoUpdata = this.StopAutoUpdate; this.ChartDestory=function() { if (this.JSChartContainer && typeof (this.JSChartContainer.ChartDestory) == 'function') { JSConsole.Chart.Log("[JSChart::ChartDestory]"); this.JSChartContainer.ChartDestory(); } } this.CreateSimpleChart = function (option) { var chart = new SimlpleChartContainer(this.CanvasElement); if (option.MainDataControl) chart.MainDataControl = option.MainDataControl; if (option.FrameType > 0) chart.FrameType = option.FrameType; if (!isNaN(option.SplitCount)) chart.YSplitCount = option.SplitCount; chart.Create(); if (option.Border) //边框设置 { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left = option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right = option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top = option.Border.Top; if (!isNaN(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom = option.Border.Bottom; if (!isNaN(option.Border.TitleHeight)) chart.Frame.ChartBorder.TitleHeight = option.Border.TitleHeight; } if (option.XFontType) chart.Frame.XFontType = option.XFontType; if (option.Frame) { if (option.Frame[0].MaxDistanceWidth) chart.Frame.MaxDistanceWidth = option.Frame[0].MaxDistanceWidth; if (option.Frame[0].IsShowBorder != null) chart.Frame.IsShowBorder = option.Frame[0].IsShowBorder; if (option.Frame[0].StringFormat) chart.Frame.YSplitOperator.StringFormat = option.Frame[0].StringFormat; if (option.Frame[0].FloatPrecision >= 0) chart.Frame.YSplitOperator.FloatPrecision = option.Frame[0].FloatPrecision; if (option.Frame[0].IgnoreYValue) chart.Frame.YSplitOperator.IgnoreYValue = option.Frame[0].IgnoreYValue; } chart.Draw(); chart.RequestData(); this.JSChartContainer = chart; this.JSChartContainer.Draw(); } //创建饼图 this.CreatePieChart = function (option) { var chart = new PieChartContainer(this.CanvasElement); if (option.MainDataControl) chart.MainDataControl = option.MainDataControl; if (option.Radius) chart.Radius = option.Radius; chart.Create(); if (option.Border) //边框设置 { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left = option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right = option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top = option.Border.Top; if (!isNaN(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom = option.Border.Bottom; } if (option.Frame) { if (option.Frame[0].IsShowBorder == false) chart.Frame.IsShowBorder = option.Frame[0].IsShowBorder; } chart.Draw(); chart.RequestData(); this.JSChartContainer = chart; this.JSChartContainer.Draw(); } //中国地图 this.CreateMapChart = function (option) { var chart = new MapChartContainer(this.CanvasElement); if (option.MainDataControl) chart.MainDataControl = option.MainDataControl; chart.Create(); if (option.Border) //边框设置 { if (!isNaN(option.Border.Left)) chart.Frame.ChartBorder.Left = option.Border.Left; if (!isNaN(option.Border.Right)) chart.Frame.ChartBorder.Right = option.Border.Right; if (!isNaN(option.Border.Top)) chart.Frame.ChartBorder.Top = option.Border.Top; if (!isNaN(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom = option.Border.Bottom; } if (option.Frame) { if (option.Frame[0].IsShowBorder == false) chart.Frame.IsShowBorder = option.Frame[0].IsShowBorder; } chart.Draw(); chart.RequestData(); this.JSChartContainer = chart; this.JSChartContainer.Draw(); } this.OnTouchStart = function (e) { if (this.JSChartContainer) this.JSChartContainer.ontouchstart(e); } this.OnTouchMove = function (e) { if (this.JSChartContainer) this.JSChartContainer.ontouchmove(e); } this.OnTouchEnd = function (e) { if (this.JSChartContainer) this.JSChartContainer.ontouchend(e); } this.SaveToImage = function (callback) { if (this.JSChartContainer && typeof (this.JSChartContainer.SaveToImage) == 'function') this.JSChartContainer.SaveToImage(callback); } this.EnableSplashScreen=function(option) { if(this.JSChartContainer && typeof(this.JSChartContainer.EnableSplashScreen)=='function') this.JSChartContainer.EnableSplashScreen(option); } } //初始化 JSChart.Init = function (uielement) { JSConsole.Chart.Log('[JSChart.Init] uielement', uielement); var jsChartControl = new JSChart(uielement); jsChartControl.OnSize(); return jsChartControl; } JSChart.SetDomain = function (domain, cacheDomain) { if (domain) { g_JSChartResource.Domain = domain; g_JSChartResource.Index.StockHistoryDayApiUrl = domain + "/API/StockHistoryDay"; //历史数据api g_JSChartResource.Index.MarketLongShortApiUrl = domain + "/API/FactorTiming"; //市场多空 g_JSChartResource.Index.MarketAttentionApiUrl = domain + "/API/MarketAttention"; //市场关注度 g_JSChartResource.Index.MarketHeatApiUrl = domain + "/API/MarketHeat"; //行业,指数热度 } if (cacheDomain) g_JSChartResource.CacheDomain = cacheDomain; JSCommonComplier.JSComplier.SetDomain(domain, cacheDomain); //编译器数据api域名修改 } //自定义风格 JSChart.SetStyle = function (style) { if (style) g_JSChartResource.SetStyle(style); } JSChart.GetResource = function () //获取颜色配置 (设置配必须啊在JSChart.Init()之前) { return g_JSChartResource; } JSChart.GetKLineZoom = function () //K线缩放配置 { return ZOOM_SEED; } JSChart.GetChinaFuturesTimeData=function() //获取国内期货交易时间配置 { return g_FuturesTimeData; } JSChart.GetInternalTimeData=function(name) //内置品种交易时间 { switch(name) { case "NYMEXTimeData": //纽约商业交易所 return g_NYMEXTimeData; case "COMEXTimeData": //纽约商品交易所 return g_COMEXTimeData; case "NYBOTTimeData": //纽约期货交易所 return g_NYBOTTimeData; case "CBOTTimeData": //芝加哥期货交易所 return g_CBOTTimeData; case "LMETimeData": //伦敦金属交易所 return g_LMETimeData; case "FuturesTimeData": //国内期货 return g_FuturesTimeData; default: return null; } } JSChart.GetDivTooltipDataFormat=function() //div tooltip数据格式化 { return g_DivTooltipDataForamt; } var JSCHART_OPERATOR_ID = { OP_SCROLL_LEFT: 1, OP_SCROLL_RIGHT: 2, OP_ZOOM_OUT: 3, //缩小 OP_ZOOM_IN: 4, //放大 OP_GOTO_HOME: 5, //第1页数据 } /* 图形控件 */ function JSChartContainer(uielement) { this.ClassName = 'JSChartContainer'; var _self = this; this.Frame; //框架画法 this.ChartPaint = new Array(); //图形画法 this.ChartPaintEx = []; //图形扩展画法 this.ChartInfo = new Array(); //K线上信息地雷 this.ChartInfoPaint; //信息地理 this.ExtendChartPaint = new Array(); //扩展画法 this.TitlePaint = new Array(); //标题画法 this.OverlayChartPaint = new Array(); //叠加信息画法 this.ChartDrawPicture = new Array(); //画图工具 this.CurrentChartDrawPicture = null; //当前的画图工具 this.SelectChartDrawPicture = null; //当前选中的画图 this.ChartCorssCursor; //十字光标 this.IsClickShowCorssCursor = false; //手势点击显示十字光标 this.ChartSplashPaint = null; //等待提示 this.LoadDataSplashTitle = '数据加载中'; this.Canvas = uielement.GetContext("2d"); //画布 this.UIElement = uielement; this.MouseDrag; this.DragMode = 1; //拖拽模式 0 禁止拖拽 1 数据拖拽 2 区间选择 this.PhoneTouchInfo; //手机手势信息 {Start:起始点, End:结束点} this.EnableScrollUpDown=false; //是否可以上下滚动图形(手机端才有) this.TouchTimer = null; //触屏定时器 this.LastDrawStatus; //最后一次画的状态 this.LastDrawID=1; //最后一次画的ID this.SnapshotType = 0; this.CursorIndex = 0; //十字光标X轴索引 this.LastPoint = new Point(); //鼠标位置 this.IsForceLandscape = false; //是否强制横屏 this.CorssCursorTouchEnd = false; //手离开屏幕自动隐藏十字光标 this.EnableAnimation = false; //是否开启动画 //坐标轴风格方法 double-更加数值型分割 price-更加股票价格分割 this.FrameSplitData = new Map(); this.FrameSplitData.set("double", new SplitData()); this.FrameSplitData.set("price", new PriceSplitData()); this.UpdateUICallback; //数据到达通知前端 this.IsOnTouch = false; //当前是否正式手势操作 this.IsFullDraw=false; //是否使用重绘模式 (可能会卡) this.LanguageID = JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; //公共函数转发,不然要导出麻烦 this.FormatDateString = IFrameSplitOperator.FormatDateString; this.FormatValueString = IFrameSplitOperator.FormatValueString; this.ToFixedPoint = ToFixedPoint; this.ToFixedRect = ToFixedRect; this.FormatTimeString = IFrameSplitOperator.FormatTimeString; //this.JSCHART_EVENT_ID = JSCHART_EVENT_ID; //事件回调 this.mapEvent = new Map(); //通知外部调用 key:JSCHART_EVENT_ID value:{Callback:回调,} this.NetworkFilter; //网络请求回调 function(data, callback); this.IsDestroy=false; //是否已经销毁了 //手势移动 十字光标 this.LastMovePoint; this.DrawMoveTimer=null; this.DrawMoveWaitTime=60; //双击缩放附图窗口 this.EnableZoomIndexWindow=false; //是否支持双击缩放附图窗口 this.PhoneDBClick=new PhoneDBClick(); this.ChartDestory=function() //销毁 { this.IsDestroy=true; this.StopAutoUpdate(); if (this.GetLatestVersionTimer!=null) { clearTimeout(this.GetLatestVersionTimer); this.GetLatestVersionTimer=null; } } this.GetLatestVersionTimer=null; //获取最新版本 this.GetLatestVersion=function() { var waittimer=1000*60*3.5; var value="aHR0cHM6Ly9ocWNoYXJ0LnplYWxpbmsuY29tL2FwaS9HZXRWZXJzaW9u"; this.GetLatestVersionTimer = setTimeout(()=> { var width=0, height=0; if (this.Frame && this.Frame.ChartBorder) { width=this.Frame.ChartBorder.GetChartWidth(); height=this.Frame.ChartBorder.GetChartHeight(); } var url=`${atob(value)}?width=${width}&height=${height}&type=uniapp`; wx.request({ url: url, method:"get", dataType: "json", async:true, success:function(data) { //TODO:判断是否是最新版本 }, fail:function(request, textStatus, errorThrown) { JSConsole.Chart.Log("[JSChartContainer::GetLatestVersion] Get HQChart latest version failed.", request); } }); }, waittimer); } this.AddEventCallback = function (object) //设置事件回调 {event:事件id, callback:回调函数} { if (!object || !object.event || !object.callback) return; var data = { Callback: object.callback, Source: object }; this.mapEvent.set(object.event, data); } this.RemoveEventCallback = function (eventid) { if (!this.mapEvent.has(eventid)) return; this.mapEvent.delete(eventid); } this.GetEvent=function(eventId) { if (!this.mapEvent.has(eventId)) return null; var item = this.mapEvent.get(eventId); return item; } this.GetEventCallback=this.GetEvent; this.GetIndexEvent = function () { return this.GetEvent(JSCHART_EVENT_ID.RECV_INDEX_DATA); } //接收指标数据 this.GetBarrageEvent=function() { return this.GetEvent(JSCHART_EVENT_ID.BARRAGE_PLAY_END);} //获取弹幕事件 this.GetEnableSplashEvent=function() { return this.GetEvent(JSCHART_EVENT_ID.ON_ENABLE_SPLASH_DRAW); } //开启/关闭文字提示信息事件 //判断是单个手指 this.IsPhoneDragging = function (e) { // JSConsole.Chart.Log(e); var changed = e.changedTouches.length; var touching = e.touches.length; return changed == 1 && touching == 1; } //是否是2个手指操所 this.IsPhonePinching = function (e) { var changed = e.changedTouches.length; var touching = e.touches.length; return (changed == 1 || changed == 2) && touching == 2; } this.IsSingleTouch=function(e) //是否是单点触屏 { var touchCount=e.touches.length; return touchCount==1; } this.GetToucheData = function (e, isForceLandscape) { var touches = new Array(); for (var i = 0; i < e.touches.length; ++i) { var item = e.touches[i]; if (isForceLandscape) { touches.push( { clientX: item.y, clientY: item.x, pageX: item.y, pageY: item.x }); } else { touches.push( {clientX: item.x, clientY: item.y, pageX: item.x, pageY: item.y }); } } return touches; } this.ClearDrawMoveTimer=function() { if (this.DrawMoveTimer != null) { clearTimeout(this.DrawMoveTimer); this.DrawMoveTimer=null; } } this.ClearTouchTimer=function() { if (this.TouchTimer != null) { clearTimeout(this.TouchTimer); this.TouchTimer=null; } } //手机拖拽 this.ontouchstart = function (e) { if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return; var jsChart = this; //if (jsChart.DragMode == 0) return; jsChart.IsOnTouch=true; jsChart.PhonePinch = null; if (this.IsPhoneDragging(e)) { if (jsChart.TryClickLock || this.TryClickIndexTitle) { var touches = this.GetToucheData(e, jsChart.IsForceLandscape); var x = touches[0].clientX; var y = touches[0].clientY; if (jsChart.TryClickLock && jsChart.TryClickLock(x, y)) return; if (jsChart.TryClickIndexTitle && jsChart.TryClickIndexTitle(x, y)) return; } //长按2秒,十字光标 if (this.TouchTimer != null) clearTimeout(this.TouchTimer); if (this.ChartCorssCursor.IsShow == true) { this.TouchTimer = setTimeout(function () { if (drag.Click.X == drag.LastMove.X && drag.Click.Y == drag.LastMove.Y) //手指没有移动,出现十字光标 { var mouseDrag = jsChart.MouseDrag; jsChart.MouseDrag = null; //移动十字光标 var x = drag.Click.X; var y = drag.Click.Y; if (jsChart.IsForceLandscape) y = jsChart.UIElement.Height - drag.Click.Y; //强制横屏Y计算 jsChart.OnMouseMove(x, y, e); } }, 800); } var drag = { "Click": {}, "LastMove": {}, //最后移动的位置 }; var touches = this.GetToucheData(e, jsChart.IsForceLandscape); drag.Click.X = touches[0].clientX; drag.Click.Y = touches[0].clientY; drag.LastMove.X = touches[0].clientX; drag.LastMove.Y = touches[0].clientY; if (jsChart.DragMode == 1) jsChart.MouseDrag = drag; this.PhoneTouchInfo={ Start:{X:touches[0].clientX, Y:touches[0].clientY }, End:{ X:touches[0].clientX, Y:touches[0].clientY } }; if (this.EnableZoomIndexWindow) { this.PhoneDBClick.AddTouchStart(touches[0].clientX, touches[0].clientY, Date.now()); JSConsole.Chart.Log("[JSChartContainer::OnTouchStart] PhoneDBClick ", this.PhoneDBClick); } if (jsChart.IsClickShowCorssCursor) { var x = drag.Click.X; var y = drag.Click.Y; jsChart.OnMouseMove(x, y, e,true); } this.TouchEvent({ EventID:JSCHART_EVENT_ID.ON_PHONE_TOUCH, FunctionName:"OnTouchStart"}, e); } else if (this.IsPhonePinching(e)) { var phonePinch = { "Start": {}, "Last": {} }; var touches = this.GetToucheData(e, jsChart.IsForceLandscape); phonePinch.Start = { "X": touches[0].pageX, "Y": touches[0].pageY, "X2": touches[1].pageX, "Y2": touches[1].pageY }; phonePinch.Last = { "X": touches[0].pageX, "Y": touches[0].pageY, "X2": touches[1].pageX, "Y2": touches[1].pageY }; jsChart.PhonePinch = phonePinch; } } this.ontouchmove = function (e) { if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return; var jsChart = this; var touches = this.GetToucheData(e, jsChart.IsForceLandscape); if (this.IsPhoneDragging(e)) { var drag = jsChart.MouseDrag; if (drag == null) { var x = touches[0].clientX; var y = touches[0].clientY; this.LastMovePoint={ X:x, Y:y }; if (this.DrawMoveTimer) return; this.DrawMoveTimer=setTimeout(()=> { if (!this.LastMovePoint) return; this.OnMouseMove(this.LastMovePoint.X, this.LastMovePoint.Y, e); this.DrawMoveTimer=null; }, this.DrawMoveWaitTime); } else { var moveSetp = Math.abs(drag.LastMove.X - touches[0].clientX); moveSetp = parseInt(moveSetp); if (jsChart.DragMode == 1) //数据左右拖拽 { if (moveSetp < 5) return; var isLeft = true; if (drag.LastMove.X < touches[0].clientX) isLeft = false;//右移数据 if (jsChart.DataMove(moveSetp, isLeft)) { jsChart.UpdataDataoffset(); jsChart.UpdatePointByCursorIndex(); jsChart.UpdateFrameMaxMin(); jsChart.ResetFrameXYSplit(); jsChart.Draw(); } else { if (jsChart.DragDownloadData) jsChart.DragDownloadData(); } drag.LastMove.X = touches[0].clientX; drag.LastMove.Y = touches[0].clientY; } } if (this.PhoneTouchInfo) { this.PhoneTouchInfo.End.X=touches[0].clientX; this.PhoneTouchInfo.End.Y=touches[0].clientY; } } else if (this.IsPhonePinching(e)) { var phonePinch = jsChart.PhonePinch; if (!phonePinch) return; if (this.EnableZoomUpDown && this.EnableZoomUpDown.Touch===false) return; var yHeight = Math.abs(touches[0].pageY - touches[1].pageY); var yLastHeight = Math.abs(phonePinch.Last.Y - phonePinch.Last.Y2); var yStep = yHeight - yLastHeight; var xHeight = Math.abs(touches[0].pageX - touches[1].pageX); var xLastHeight = Math.abs(phonePinch.Last.X - phonePinch.Last.X2); var xStep = xHeight - xLastHeight; var minStep=this.ZoomStepPixel; if (Math.abs(yStep) < minStep && Math.abs(xStep) < minStep) return; var step = yStep; if (Math.abs(yStep) < minStep) step = xStep; if (step > 0) //放大 { var cursorIndex = {}; cursorIndex.Index = parseInt(Math.abs(jsChart.CursorIndex - 0.5).toFixed(0)); if (!jsChart.Frame.ZoomUp(cursorIndex)) return; jsChart.CursorIndex = cursorIndex.Index; jsChart.UpdatePointByCursorIndex(); jsChart.UpdataDataoffset(); jsChart.UpdateFrameMaxMin(); jsChart.ResetFrameXYSplit(); jsChart.Draw(); } else //缩小 { var cursorIndex = {}; cursorIndex.Index = parseInt(Math.abs(jsChart.CursorIndex - 0.5).toFixed(0)); if (!jsChart.Frame.ZoomDown(cursorIndex)) return; jsChart.CursorIndex = cursorIndex.Index; jsChart.UpdataDataoffset(); jsChart.UpdatePointByCursorIndex(); jsChart.UpdateFrameMaxMin(); jsChart.ResetFrameXYSplit(); jsChart.Draw(); } phonePinch.Last = { "X": touches[0].pageX, "Y": touches[0].pageY, "X2": touches[1].pageX, "Y2": touches[1].pageY }; } } this.ontouchend = function (e) { if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return; if (this.EnableZoomIndexWindow) { var time=Date.now(); this.PhoneDBClick.AddTouchEnd(time); if (this.PhoneDBClick.IsVaildDBClick()) { this.OnTouchDBClick(this.PhoneDBClick.Start); this.PhoneDBClick.Clear(); } } this.IsOnTouch = false; this.LastMovePoint=null; JSConsole.Chart.Log('[JSChartContainer:ontouchend] IsOnTouch=' + this.IsOnTouch +' LastDrawStatus=' + this.LastDrawStatus); this.ClearDrawMoveTimer(); this.ClearTouchTimer(); this.TouchEvent({ EventID:JSCHART_EVENT_ID.ON_PHONE_TOUCH, FunctionName:"OnTouchEnd"}, e); this.Draw();//手放开 重新绘制 } this.OnTouchDBClick=function(points) { var x=points[0].X, y=points[0].Y; JSConsole.Chart.Log('[JSChartContainer:OnTouchDBClick] Phone dbclick', x, y); var frameId=this.Frame.PtInFrame(x,y); JSConsole.Chart.Log("[JSChartContainer::OnTouchDBClick] frameId",frameId); if (frameId>=this.Frame.ZoomStartWindowIndex) { if (this.ZoomIndexWindow(frameId, {X:x, Y:y})) { this.Frame.SetSizeChage(true); this.Draw(); return true; } } return false; } this.ZoomIndexWindow=function(frameID, option) //最大化/最小化指标窗口 { if (frameID<0 || frameID>=this.Frame.SubFrame.length) return false; return this.Frame.ZoomIndexWindow(frameID, option); } this.TouchEvent=function(obj,e) { var eventID=obj.EventID; var event=this.GetEvent(eventID); if (!event || !event.Callback) return false; var drag=this.PhoneTouchInfo if (!drag || !drag.Start || !drag.End ) return false; var clientX=drag.End.X; var clientY=drag.End.Y; var x=drag.End.X; var y=drag.End.Y; var data= { X:clientX, Y:clientY, FrameID:-1, FunctionName:obj.FunctionName, Drag: { Start:{ X:drag.Start.X, Y:drag.Start.Y }, End:{ X:drag.End.X, Y:drag.End.Y } } }; var isInClient=false; var rtClient = new Rect(this.Frame.ChartBorder.GetLeft(), this.Frame.ChartBorder.GetTop(), this.Frame.ChartBorder.GetWidth(), this.Frame.ChartBorder.GetHeight()); isInClient = rtClient.IsPointIn(x, y); if (isInClient) { var yValueExtend={}; var yValue=this.Frame.GetYData(y,yValueExtend); if (IFrameSplitOperator.IsNumber(yValueExtend.FrameID) && yValueExtend.FrameID>=0) { var xValue=this.Frame.GetXData(x); data.FrameID=yValueExtend.FrameID; data.Data={ X:xValue, Y:yValue } ; } } event.Callback(event, data, this); return true; } this.FullDraw=function(drawType) { var self = this; this.Canvas.clearRect(0, 0, this.UIElement.Width, this.UIElement.Height); if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash) //动画 { this.Frame.ClearCoordinateText(); this.Frame.Draw(); //框架 this.ChartSplashPaint.Draw(); this.LastDrawStatus = 'FullDraw'; this.Canvas.draw(); return; } this.Frame.SetDrawOtherChart(() => { for (var i in this.ExtendChartPaint) { var item = this.ExtendChartPaint[i]; if (item.IsCallbackDraw) item.Draw(); } }); this.Frame.Draw(); //框架 if (this.Frame.DrawCustomVertical) { var eventCVericalDraw = this.GetEvent(JSCHART_EVENT_ID.ON_CUSTOM_VERTICAL_DRAW); this.Frame.DrawCustomVertical(eventCVericalDraw); } for (var i in this.ChartPaint) //图形 { var item = this.ChartPaint[i]; if (item.IsDrawFirst) item.Draw(); } for (var i in this.ChartPaint) //图形2 框架内图形 { var item = this.ChartPaint[i]; if (!item.IsDrawFirst) item.Draw(); } for (var i in this.ChartPaintEx) //扩展图形 { var item = this.ChartPaintEx[i]; item.Draw(); } for (var i in this.OverlayChartPaint) //叠加股票 { var item = this.OverlayChartPaint[i]; item.Draw(); } if (this.Frame.DrawInsideHorizontal) this.Frame.DrawInsideHorizontal(); //框架内部坐标 if (this.Frame.DrawCustomHorizontal) this.Frame.DrawCustomHorizontal(); if (this.ChartInfoPaint) this.ChartInfoPaint.Draw(); this.Frame.DrawLock(); var bOnTouchDraw=drawType == 'DrawDynamicInfo' || this.IsOnTouch; if (bOnTouchDraw) { if (self.ChartCorssCursor) //十字光标 { self.ChartCorssCursor.LastPoint = self.LastPoint; self.ChartCorssCursor.CursorIndex = self.CursorIndex; self.ChartCorssCursor.Draw(); } } var eventTitleDraw = this.GetEvent(JSCHART_EVENT_ID.ON_TITLE_DRAW); var eventIndexTitleDraw = this.GetEvent(JSCHART_EVENT_ID.ON_INDEXTITLE_DRAW); for (var i in self.TitlePaint) //标题 { var item = self.TitlePaint[i]; if (!item.IsDynamic) continue; if (item.ClassName == 'DynamicChartTitlePainting') item.OnDrawEvent = eventIndexTitleDraw else item.OnDrawEvent = eventTitleDraw; item.CursorIndex = self.CursorIndex; if (!bOnTouchDraw) //手势离开屏幕 去最后一个数据 { if (this.ChartPaint[0] && this.ChartPaint[0].Data && this.ChartPaint[0].Data.Data) { var hisData=this.ChartPaint[0].Data; var dataCount=hisData.Data.length; if (dataCount>0) item.CursorIndex=((dataCount-1)-hisData.DataOffset); } } if (item.FullDraw) item.FullDraw(); } if (bOnTouchDraw) { for (var i in this.ExtendChartPaint) //动态扩展图形 在动态标题以后画 { var item = this.ExtendChartPaint[i]; if (item.IsCallbackDraw) continue; item.LatestPoint={ X:this.LastPoint.X, Y:this.LastPoint.Y }; if (item.IsDynamic && item.DrawAfterTitle) item.Draw(); } } this.LastDrawStatus = 'FullDraw'; this.Canvas.draw(false); } this.Draw = function () { if (this.IsFullDraw) { this.FullDraw('Draw'); return; } if (this.IsOnTouch == true && (this.ClassName == 'MinuteChartContainer' || this.ClassName =='MinuteChartHScreenContainer')) return; var self = this; this.Canvas.clearRect(0, 0, this.UIElement.Width, this.UIElement.Height); this.Frame.SetDrawOtherChart(() => { for (var i in this.ExtendChartPaint) { var item = this.ExtendChartPaint[i]; if (item.IsCallbackDraw) item.Draw(); } }); //框架 this.Frame.Draw(); if (this.Frame.DrawCustomVertical) { var eventCVericalDraw = this.GetEvent(JSCHART_EVENT_ID.ON_CUSTOM_VERTICAL_DRAW); this.Frame.DrawCustomVertical(eventCVericalDraw); } if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash) { this.Frame.DrawInsideHorizontal(); this.ChartSplashPaint.Draw(); this.LastDrawStatus = 'Draw'; this.Canvas.draw(); return; } for (var i in this.ChartPaint) { var item = this.ChartPaint[i]; if (item.IsDrawFirst) item.Draw(); } //框架内图形 for (var i in this.ChartPaint) { var item = this.ChartPaint[i]; if (!item.IsDrawFirst) item.Draw(); } for (var i in this.ChartPaintEx) { var item = this.ChartPaintEx[i]; item.Draw(); } //叠加股票 for (var i in this.OverlayChartPaint) { var item = this.OverlayChartPaint[i]; item.Draw(); } //框架外图形 for (var i in this.ExtendChartPaint) { var item = this.ExtendChartPaint[i]; if (item.IsCallbackDraw) continue; if (!item.IsDynamic && !item.IsAnimation) item.Draw(); } //框架内部坐标 if (this.Frame.DrawInsideHorizontal) this.Frame.DrawInsideHorizontal(); if (this.Frame.DrawCustomHorizontal) this.Frame.DrawCustomHorizontal(); if (this.ChartInfoPaint) this.ChartInfoPaint.Draw(); this.Frame.DrawLock(); var eventTitleDraw = this.GetEvent(JSCHART_EVENT_ID.ON_TITLE_DRAW); var eventIndexTitleDraw = this.GetEvent(JSCHART_EVENT_ID.ON_INDEXTITLE_DRAW); for (var i in this.TitlePaint) { var item = this.TitlePaint[i]; if (!item.IsDynamic) continue; if (item.ClassName == 'DynamicChartTitlePainting') item.OnDrawEvent = eventIndexTitleDraw else item.OnDrawEvent = eventTitleDraw; if (typeof (item.DrawTitle) == 'function') item.DrawTitle(); } this.LastDrawStatus='Draw'; if (this.IsOnTouch) //手势移动的时候不保存图片 { this.Canvas.draw(false); } else { ++this.LastDrawID; //坑!!.画图是异步, 保存当前屏图放在回调里面 //JSConsole.Chart.Log('[JSChartContainer:Draw][ID=' + this.UIElement.ID + '] draw and save snapshot. DrawID=' + this.LastDrawID + ' .....'); var lastDrawID=this.LastDrawID; this.Canvas.draw(false, function () { //if (lastDrawID == self.LastDrawID) self.Frame.Snapshot(self.SnapshotType); //只保存最后一次的截图 //JSConsole.Chart.Log('[JSChartContainer:Draw] finish. DrawID('+ lastDrawID +','+ self.LastDrawID +')'); }); } //JSConsole.Chart.Log('[JSChartContainer:Draw][ID=' + this.UIElement.ID + '] draw dynamic info ......'); //动态标题都不画了(Canvas.draw 异步画的,如果下面再画会被截屏进去) 只有数据移动的时候在画 } //画动态信息 this.TempImage=null; this.DrawDynamicInfo = function () { if (this.IsFullDraw) { this.FullDraw('DrawDynamicInfo'); return; } var self = this; var width = this.Frame.ChartBorder.GetChartWidth(); var height = this.Frame.ChartBorder.GetChartHeight(); if (self.SnapshotType==1) { if (this.Frame.ScreenImageData == null) return; wx.canvasPutImageData({ canvasId: this.UIElement.ID, x: 0,y: 0,width: width,height: height, data: this.Frame.ScreenImageData, success(res) { self.DrawDynamicChart(true); } }) } else { if (this.Frame.ScreenImagePath == null) return; if (self.Canvas && self.Canvas.DomNode) //新版本2D画布 { //JSConsole.Chart.Log("[DrawDynamicInfo] ScreenImagePath ", this.Frame.ScreenImagePath); if (!this.TempImage) this.TempImage= self.Canvas.DomNode.createImage(); //新版本的必须要装成image类 比较坑 this.TempImage.src = this.Frame.ScreenImagePath; //JSConsole.Chart.Log("[DrawDynamicInfo] tempImage ", this.TempImage); this.TempImage.onload=()=> { //JSConsole.Chart.Log("[DrawDynamicInfo] onload ", self.TempImage); self.Canvas.clearRect(0, 0, width, height); self.Canvas.drawImage(self.TempImage, 0, 0, width, height); self.DrawDynamicChart(false); } } else { self.Canvas.drawImage(this.Frame.ScreenImagePath, 0, 0, width, height); self.DrawDynamicChart(false); } } } this.DrawDynamicChart = function (bReserve) { var self = this; if (self.ChartCorssCursor) { self.ChartCorssCursor.LastPoint = self.LastPoint; self.ChartCorssCursor.CursorIndex = self.CursorIndex; self.ChartCorssCursor.Draw(); } for (var i in self.TitlePaint) { var item = self.TitlePaint[i]; if (!item.IsDynamic) continue; item.CursorIndex = self.CursorIndex; item.Draw(); } for (var i in this.ExtendChartPaint) //动态扩展图形 在动态标题以后画 { var item = this.ExtendChartPaint[i]; if (item.IsDynamic && item.DrawAfterTitle) item.Draw(); } if (this.EnableAnimation) { for (var i in this.ExtendChartPaint) //动画 { var item = this.ExtendChartPaint[i]; if (item.IsAnimation === true) item.Draw(); } } this.LastDrawStatus = 'DrawDynamicInfo'; JSConsole.Chart.Log('[JSChartContainer:DrawDynamicChart][ID=' + this.UIElement.ID + '] draw .....'); self.Canvas.draw(bReserve, function () { JSConsole.Chart.Log('[JSChartContainer:DrawDynamicChart] finish.'); }); } this.DrawAnimation = function () //绘制动画 如弹幕 { if (!this.EnableAnimation) return; if (this.Frame.ScreenImagePath && !this.IsOnTouch) { for (var i in this.ExtendChartPaint) { var item = this.ExtendChartPaint[i]; if (item.IsAnimation === true) item.IsMoveStep = true; //移动弹幕 } this.DrawDynamicInfo(); } var self = this; this.UIElement.WebGLCanvas.requestAnimationFrame(() => { this.DrawAnimation(); }); } this.StartAnimation = function (option) { JSConsole.Chart.Log('[JSChartContainer::StartAnimation] ', this.UIElement.WebGLCanvas); if (!this.UIElement.WebGLCanvas) return; var bCreated = false; //是否已经创建了弹幕画法 var barrageData = null; for (var i in this.ExtendChartPaint) { var item = this.ExtendChartPaint[i]; if (item.ClassName === 'BarragePaint') { bCreated = true; barrageData = item.BarrageList; break; } } if (!bCreated) { var chart = new BarragePaint(); chart.Canvas = this.Canvas; chart.ChartBorder = this.Frame.ChartBorder; chart.ChartFrame = this.Frame; chart.HQChart = this; chart.SetOption(option); this.ExtendChartPaint.push(chart); barrageData = chart.BarrageList; } this.EnableAnimation = true; var self = this; this.UIElement.WebGLCanvas.requestAnimationFrame(()=> { this.DrawAnimation(); }); return barrageData; } this.StopAnimation = function () { this.EnableAnimation = false; this.DrawDynamicInfo(); } this.OnMouseMove = function (x, y, e, bFullDraw) { var lastY = this.LastPoint.Y; this.LastPoint.X = x; this.LastPoint.Y = y; var lastCursorIndex = this.CursorIndex; this.CursorIndex = this.Frame.GetXData(x); if ( this.ClassName=="KLineChartContainer" || this.ClassName=="KLineChartHScreenContainer" ) { if (lastCursorIndex == this.CursorIndex && Math.abs(lastY - y) < 1) return; //一个一个数据移动 } else { if (parseInt(lastCursorIndex - 0.5) == parseInt(this.CursorIndex - 0.5) && Math.abs(lastY - y) < 1) return; //一个一个数据移动 } if (bFullDraw) { this.FullDraw(); } else { if (this.IsForceLandscape) this.Draw();//横屏图片太大不让贴,分两张图贴,多次截图的函数是坏的, 直接重画了 else this.DrawDynamicInfo(); } } this.OnDoubleClick = function (x, y, e) { //JSConsole.Chart.Log(e); } this.UpdatePointByCursorIndex = function () { this.LastPoint.X = this.Frame.GetXFromIndex(this.CursorIndex); var index = Math.abs(this.CursorIndex - 0.5); index = parseInt(index.toFixed(0)); if (this.ClassName == 'KLineChartContainer') index = this.CursorIndex; var data = this.Frame.Data; if (data.DataOffset + index >= data.Data.length) { return; } var close = data.Data[data.DataOffset + index].Close; this.LastPoint.Y = this.Frame.GetYFromData(close); } this.ResetFrameXYSplit = function () { if (typeof (this.Frame.ResetXYSplit) == 'function') this.Frame.ResetXYSplit(); } this.UpdateFrameMaxMin = function () { var frameMaxMinData = new Array(); var chartPaint = new Array(); for (var i in this.ChartPaint) { var item=this.ChartPaint[i]; if (item.IsShow==false) continue; //隐藏的图形不计算 chartPaint.push(item); } for (var i in this.OverlayChartPaint) { chartPaint.push(this.OverlayChartPaint[i]); } for (var i in chartPaint) { var paint = chartPaint[i]; var range = paint.GetMaxMin(); if (range == null || range.Max == null || range.Min == null) continue; var frameItem = null; for (var j in frameMaxMinData) { if (frameMaxMinData[j].Frame == paint.ChartFrame) { frameItem = frameMaxMinData[j]; break; } } if (frameItem) { if (frameItem.Range.Max < range.Max) frameItem.Range.Max = range.Max; if (frameItem.Range.Min > range.Min) frameItem.Range.Min = range.Min; } else { frameItem = {}; frameItem.Frame = paint.ChartFrame; frameItem.Range = range; frameMaxMinData.push(frameItem); } } for (var i in frameMaxMinData) { var item = frameMaxMinData[i]; if (!item.Frame || !item.Range) continue; if (item.Range.Max == null || item.Range.Min == null) continue; if (item.Frame.YSpecificMaxMin) { item.Frame.HorizontalMax = item.Frame.YSpecificMaxMin.Max; item.Frame.HorizontalMin = item.Frame.YSpecificMaxMin.Min; } else { item.Frame.HorizontalMax = item.Range.Max; item.Frame.HorizontalMin = item.Range.Min; } item.Frame.XYSplit = true; } } this.DataMoveLeft = function () { var data = null; if (!this.Frame.Data) data = this.Frame.Data; else data = this.Frame.SubFrame[0].Frame.Data; if (!data) return false; if (data.DataOffset <= 0) return false; --data.DataOffset; return true; } this.DataMoveRight = function () { var data = null; if (!this.Frame.Data) data = this.Frame.Data; else data = this.Frame.SubFrame[0].Frame.Data; if (!data) return false; var xPointcount = 0; if (this.Frame.XPointCount) xPointcount = this.Frame.XPointCount; else xPointcount = this.Frame.SubFrame[0].Frame.XPointCount; if (!xPointcount) return false; if (xPointcount + data.DataOffset >= data.Data.length) return false; ++data.DataOffset; return true; } this.UpdataDataoffset = function () { var data = null; if (this.Frame.Data) data = this.Frame.Data; else data = this.Frame.SubFrame[0].Frame.Data; if (!data) return; for (var i in this.ChartPaint) { var item = this.ChartPaint[i]; if (!item.Data) continue; item.Data.DataOffset = data.DataOffset; } for (var i in this.OverlayChartPaint) { var item = this.OverlayChartPaint[i]; if (!item.Data) continue; item.Data.DataOffset = data.DataOffset; } } this.DataMove = function (step, isLeft) { step=parseInt(step/this.StepPixel); if (step<=0) return false; var data = null; if (!this.Frame.Data) data = this.Frame.Data; else data = this.Frame.SubFrame[0].Frame.Data; if (!data) return false; var xPointcount = 0; if (this.Frame.XPointCount) xPointcount = this.Frame.XPointCount; else xPointcount = this.Frame.SubFrame[0].Frame.XPointCount; if (!xPointcount) return false; if (isLeft) //--> { if (this.RightSpaceCount > 0) { if (xPointcount + data.DataOffset >= data.Data.length + this.RightSpaceCount - 1) return false; data.DataOffset += step; if (data.DataOffset + xPointcount >= data.Data.length + this.RightSpaceCount) data.DataOffset = data.Data.length - (xPointcount - this.RightSpaceCount); } else { if (xPointcount + data.DataOffset >= data.Data.length) return false; data.DataOffset += step; if (data.DataOffset + xPointcount >= data.Data.length) data.DataOffset = data.Data.length - xPointcount; } return true; } else //<-- { if (data.DataOffset <= 0) return false; data.DataOffset -= step; if (data.DataOffset < 0) data.DataOffset = 0; return true; } } //获取鼠标在当前子窗口id this.GetSubFrameIndex = function (x, y) { if (!this.Frame.SubFrame || this.Frame.SubFrame.length <= 0) return -1; for (var i in this.Frame.SubFrame) { var frame = this.Frame.SubFrame[i].Frame; var left = frame.ChartBorder.GetLeft(); var top = frame.ChartBorder.GetTop(); var height = frame.ChartBorder.GetHeight(); var width = frame.ChartBorder.GetWidth(); this.Canvas.rect(left, top, width, height); if (this.Canvas.isPointInPath(x, y)) return parseInt(i); } return 0; } //根据X坐标获取数据索引 this.GetDataIndexByPoint = function (x) { var frame = this.Frame; if (this.Frame.SubFrame && this.Frame.SubFrame.length > 0) frame = this.Frame.SubFrame[0].Frame; var data = null; if (this.Frame.Data) data = this.Frame.Data; else data = this.Frame.SubFrame[0].Frame.Data; if (!data || !frame) return; var index = parseInt(frame.GetXData(x)); //JSConsole.Chart.Log('x='+ x +' date='+data.Data[data.DataOffset+index].Date); return data.DataOffset + index; } this.SaveToImage = function (callback) { let width = this.UIElement.Width; let height = this.UIElement.Height;; JSConsole.Chart.Log('[JSChartContainer::SaveToImage]', this.UIElement); wx.canvasToTempFilePath({ x: 0, y: 0, width: width, height: height, canvasId: this.UIElement.ID, success: function (res) { let data = { ImagePath: res.tempFilePath, Width: width, Height: height }; if (typeof (callback) == 'function') callback(data); } }) } //全屏提示信息 { Title:提示信息, Draw:false/true 是否立即重绘, } this.EnableSplashScreen=function(option) { if (!this.ChartSplashPaint) return; if (!option) return; if (IFrameSplitOperator.IsString(option.Title)) this.ChartSplashPaint.SetTitle(option.Title); this.ChartSplashPaint.EnableSplash(true); if (option.Draw===false) return; this.Draw(); } //增加一个指标窗口 this.AddIndexWindow=function(indexName,option) { //查找系统指标 let scriptData = new JSCommonIndexScript.JSIndexScript(); let indexInfo = scriptData.Get(indexName); if (!indexInfo) return; var index=this.Frame.SubFrame.length; var subFrame=this.CreateSubFrameItem(index); this.Frame.SubFrame[index]=subFrame; var titlePaint=new DynamicChartTitlePainting(); titlePaint.Frame=this.Frame.SubFrame[index].Frame; titlePaint.Canvas=this.Canvas; titlePaint.LanguageID=this.LanguageID; titlePaint.GetEventCallback=(id)=> { return this.GetEventCallback(id); } this.TitlePaint[index+1]=titlePaint; if (option) { if (option.Window) { var item=option.Window; if (item.IsDrawTitleBG==true) subFrame.Frame.IsDrawTitleBG=item.IsDrawTitleBG; } if (IFrameSplitOperator.IsNumber(option.SplitCount)) subFrame.Frame.YSplitOperator.SplitCount=option.SplitCount; if (IFrameSplitOperator.IsNumber(option.TitleHeight)) subFrame.Frame.ChartBorder.TitleHeight=option.TitleHeight; if (IFrameSplitOperator.IsBool(option.IsShowTitleArraw)) subFrame.Frame.IsShowTitleArraw=option.IsShowTitleArraw; if (IFrameSplitOperator.IsBool(option.IsShowIndexName)) subFrame.Frame.IsShowIndexName=option.IsShowIndexName; if (IFrameSplitOperator.IsBool(option.IsShowOverlayIndexName)) subFrame.Frame.IsShowOverlayIndexName=option.IsShowOverlayIndexName; if (IFrameSplitOperator.IsNumber(option.IndexParamSpace)) subFrame.Frame.IndexParamSpace=option.IndexParamSpace; if (IFrameSplitOperator.IsBool(option.IsShowXLine)) subFrame.Frame.IsShowXLine=option.IsShowXLine; if (IFrameSplitOperator.IsBool(option.IsShowYLine)) subFrame.Frame.IsShowYLine=option.IsShowYLine; if (IFrameSplitOperator.IsBool(option.IsShowIndexTitle)) subFrame.Frame.IsShowTitle=option.IsShowIndexTitle; if (IFrameSplitOperator.IsBool(option.IsShowLeftText)) subFrame.Frame.IsShowYText[0] = option.IsShowLeftText; //显示左边刻度 if (IFrameSplitOperator.IsBool(option.IsShowRightText)) subFrame.Frame.IsShowYText[1] = option.IsShowRightText; //显示右边刻度 } //最后一个显示X轴坐标 for(var i=0;i=0) indexData.FloatPrecision=option.FloatPrecision; if (option.StringFormat>0) indexData.StringFormat=option.StringFormat; if (option.Args) indexData.Args=option.Args; } this.WindowIndex[index] = new ScriptIndex(indexData.Name, indexData.Script, indexData.Args,indexData); //脚本执行 if (this.ClassName=="MinuteChartContainer" || this.ClassName=="MinuteChartHScreenContainer") var bindData=this.SourceData; else var bindData=this.ChartPaint[0].Data; this.BindIndexData(index,bindData); //执行脚本 } } function ToFixed(number, precision) { var b = 1; if (isNaN(number)) return number; if (number < 0) b = -1; var multiplier = Math.pow(10, precision); var value = Math.round(Math.abs(number) * multiplier) / multiplier * b; if (/^(\d+(?:\.\d+)?)(e)([\-]?\d+)$/.test(value)) var s = value.toFixed2(precision); else var s = value.toString(); var rs = s.indexOf('.'); if (rs < 0 && precision > 0) { rs = s.length; s += '.'; } while (s.length <= rs + precision) { s += '0'; } return s; } Number.prototype.toFixed2 = Number.prototype.toFixed; //备份下老的 Number.prototype.toFixed = function (precision) { return ToFixed(this, precision) } function Guid() { function S4() { return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); } return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4()); } function GetScrollPosition() { var scrollPos = {}; var scrollTop = 0; var scrollLeft = 0; if (document.documentElement && document.documentElement.scrollTop) { scrollTop = document.documentElement.scrollTop; scrollLeft = document.documentElement.scrollLeft; } else if (document.body) { scrollTop = document.body.scrollTop; scrollLeft = document.body.scrollLeft; } scrollPos.Top = scrollTop; scrollPos.Left = scrollLeft; return scrollPos; } //修正线段有毛刺 function ToFixedPoint(value) { //return value; return parseInt(value) + 0.5; } function ToFixedRect(value) { //return value; // With a bitwise or. //rounded = (0.5 + somenum) | 0; // A double bitwise not. //rounded = ~~ (0.5 + somenum); // Finally, a left bitwise shift. var rounded; return rounded = (0.5 + value) << 0; } function Point() { this.X; this.Y; } function SelectRectData() { this.Data; //主数据 this.JSChartContainer; //行情控件 this.Start; //数据起始位子 this.End; //数据结束位置 this.XStart;//X坐标起始位置 this.XEnd; //X位置结束为止 } //边框信息 function ChartBorder() { this.UIElement; //四周间距 this.Left = 50; this.Right = 80; this.Top = 50; this.Bottom = 50; this.TitleHeight = 15; //标题高度 //上下间距 this.TopSpace = 0; this.BottomSpace = 0; this.LeftExtendWidth=0; //左边扩展图形宽度 this.RightExtendWidth=0; this.GetBorder=function() { var data= { Left:this.Left, LeftEx:this.Left+this.LeftExtendWidth, Right:this.UIElement.width-this.Right, RightEx:this.UIElement.width-this.Right-this.RightExtendWidth, Top:this.Top, TopEx:this.Top+this.TitleHeight+this.TopSpace, TopTitle:this.Top+this.TitleHeight, Bottom:this.UIElement.height-this.Bottom, BottomEx:this.UIElement.height-this.Bottom-this.BottomSpace, ChartWidth:this.UIElement.width, ChartHeight:this.UIElement.height }; return data; } this.GetHScreenBorder=function() { var data= { Left:this.Left, LeftEx:this.Left+this.BottomSpace, Right:this.UIElement.width-this.Right, RightEx:this.UIElement.width-this.Right-this.TitleHeight- this.TopSpace, RightTitle:this.UIElement.width-this.Right-this.TitleHeight, Top:this.Top, TopEx:this.Top+this.LeftExtendWidth, Bottom:this.UIElement.height-this.Bottom, BottomEx:this.UIElement.height-this.Bottom-this.RightExtendWidth, ChartWidth:this.UIElement.width, ChartHeight:this.UIElement.height }; return data; } this.GetChartWidth = function () { return this.UIElement.Width; } this.GetChartHeight = function () { return this.UIElement.Height; } this.GetLeft = function () { return this.Left; } this.GetRight = function () { return this.UIElement.Width - this.Right; } this.GetTop = function () { return this.Top; } this.GetTopEx = function () //去掉标题,上面间距 { return this.Top + this.TitleHeight + this.TopSpace; } this.GetTopTitle = function () //去掉标题 { return this.Top + this.TitleHeight; } this.GetBottom = function () { return this.UIElement.Height - this.Bottom; } this.GetBottomEx = function () { return this.UIElement.Height - this.Bottom - this.BottomSpace; } this.GetWidth = function () { return this.UIElement.Width - this.Left - this.Right; } this.GetHeight = function () { return this.UIElement.Height - this.Top - this.Bottom; } this.GetHeightEx = function () //去掉标题的高度 上下间距 { return this.UIElement.Height - this.Top - this.Bottom - this.TitleHeight - this.TopSpace - this.BottomSpace; } this.GetRightEx = function () //横屏去掉标题高度的 上面间距 { return this.UIElement.Width - this.Right - this.TitleHeight - this.TopSpace; } this.GetWidthEx = function () //横屏去掉标题宽度 上下间距 { return this.UIElement.Width - this.Left - this.Right - this.TitleHeight - this.TopSpace - this.BottomSpace; } this.GetLeftEx = function () //横屏 { return this.Left + this.BottomSpace; } this.GetRightTitle = function ()//横屏 { return this.UIElement.Width - this.Right - this.TitleHeight; } this.GetTitleHeight = function () { return this.TitleHeight; } } function IChartFramePainting() { this.HorizontalInfo = new Array(); //Y轴 this.VerticalInfo = new Array(); //X轴 this.ClassName='IChartFramePainting'; this.Canvas; //画布 this.Identify; //窗口标识 this.ChartBorder; this.PenBorder = g_JSChartResource.FrameBorderPen; //边框颜色 this.TitleBGColor = g_JSChartResource.FrameTitleBGColor; //标题背景色 this.IsShow = true; //是否显示 this.SizeChange = true; //大小是否改变 this.XYSplit = true; //XY轴坐标信息改变 this.HorizontalMax; //Y轴最大值 this.HorizontalMin; //Y轴最小值 this.XPointCount = 10; //X轴数据个数 this.YSplitOperator; //Y轴分割 this.XSplitOperator; //X轴分割 this.Data; //主数据 this.YSpecificMaxMin = null; //指定Y轴最大最小值 this.YSplitScale=null; //固定分割刻度数组 [2,5,8] this.IsShowBorder = true; //是否显示边框 this.IsShowIndexName = true; //是否显示指标名字 this.IndexParamSpace = 2; //指标参数数值显示间距 //上锁信息 this.IsLocked = false; //是否上锁 this.LockPaint = null; this.BorderLine=null; //1=上 2=下 4=左 8=右 this.IsMinSize=false; //窗口是否最小化 this.Draw = function () { this.DrawFrame(); this.DrawBorder(); this.SizeChange = false; this.XYSplit = false; } this.DrawFrame = function () { } this.ClearCoordinateText=function(option) { if (IFrameSplitOperator.IsNonEmptyArray(this.HorizontalInfo)) { for(var i=0;i0) //上 { this.Canvas.moveTo(left,top); this.Canvas.lineTo(right,top); } if ((this.BorderLine&2)>0) //下 { this.Canvas.moveTo(left,bottom); this.Canvas.lineTo(right,bottom); } if ((this.BorderLine&4)>0) //左 { this.Canvas.moveTo(left,top); this.Canvas.lineTo(left,bottom); } if ((this.BorderLine&8)>0) //右 { this.Canvas.moveTo(right,top); this.Canvas.lineTo(right,bottom); } this.Canvas.stroke(); } } //左右刻度文字宽度 this.GetScaleTextWidth=function() { } //画标题背景色 this.DrawTitleBG = function () { /* 指标信息背景色不画,画了感觉框架变小了 if (this.ChartBorder.TitleHeight<=0) return; var left=ToFixedPoint(this.ChartBorder.GetLeft()); var top=ToFixedPoint(this.ChartBorder.GetTop()); var right=ToFixedPoint(this.ChartBorder.GetRight()); var bottom=ToFixedPoint(this.ChartBorder.GetTopEx()); var width=right-left; var height=bottom-top; this.Canvas.fillStyle=this.TitleBGColor; this.Canvas.fillRect(left,top,width,height); */ } this.DrawLock = function () { if (this.IsLocked) { if (this.LockPaint == null) this.LockPaint = new ChartLock(); this.LockPaint.Canvas = this.Canvas; this.LockPaint.ChartBorder = this.ChartBorder; this.LockPaint.ChartFrame = this; this.LockPaint.Draw(); } } //设施上锁 this.SetLock = function (lockData) { if (!lockData) //空数据不上锁 { this.IsLocked = false; return; } this.IsLocked = true; if (!this.LockPaint) this.LockPaint = new ChartLock(); //创建锁 if (lockData.Callback) this.LockPaint.Callback = lockData.Callback; //回调 if (lockData.IndexName) this.LockPaint.IndexName = lockData.IndexName; //指标名字 if (lockData.ID) this.LockPaint.LockID = lockData.ID; //锁ID if (lockData.BG) this.LockPaint.BGColor = lockData.BG; //背景色 if (lockData.Text) this.LockPaint.Title = lockData.Text; if (lockData.TextColor) this.LockPaint.TextColor = lockData.TextColor; if (lockData.Font) this.LockPaint.Font = lockData.Font; if (lockData.Count) this.LockPaint.LockCount = lockData.Count; } } //空框架只画边框 function NoneFrame() { this.newMethod = IChartFramePainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='NoneFrame'; this.Snapshot = function () { } this.DrawInsideHorizontal = function () { } this.SetSizeChage = function (sizeChange) { this.SizeChange = sizeChange; //画布的位置 this.Position = { X: this.ChartBorder.UIElement.offsetLeft, Y: this.ChartBorder.UIElement.offsetTop, W: this.ChartBorder.UIElement.clientWidth, H: this.ChartBorder.UIElement.clientHeight }; } } function AverageWidthFrame() { this.newMethod = IChartFramePainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='AverageWidthFrame'; this.DataWidth = 50; this.DistanceWidth = 10; this.MinXDistance = 30; //X轴刻度最小间距 this.MinYDistance=10; this.XMessageAlign = 'top'; //X轴刻度文字上下对齐方式 this.IsShowTitle = true; //是否显示动态标题 this.IsShowYText = [true, true]; //是否显示Y轴坐标坐标 [0=左侧] [1=右侧] this.XBottomOffset = g_JSChartResource.Frame.XBottomOffset; //X轴文字显示向下偏移 this.YTextTopOffset=g_JSChartResource.Frame.YTopOffset; //Y轴顶部文字向下偏移 this.YTextPosition=[0,0], //是坐标否强制画在内部 [0=左侧] [1=右侧] 1=OUT" , 2=INSIDE this.IsShowXLine=true; //是否显示X轴刻度线 this.IsShowYLine=true; this.YTextBaseline=0; //0=居中 1=上部 (目前就支持内部刻度) this.ShortYLineLength=5; this.ShortXLineLength=5; this.DrawOtherChart; //其他画法调用 this.DrawFrame = function () { if (this.XPointCount > 0) { this.DistanceWidth = this.ChartBorder.GetWidth() / (4 * this.XPointCount); this.DataWidth = 2 * this.DistanceWidth; } this.DrawHorizontal(); this.DrawVertical(); } this.GetYFromData = function (value) { if (value <= this.HorizontalMin) return this.ChartBorder.GetBottomEx(); if (value >= this.HorizontalMax) return this.ChartBorder.GetTopEx(); var height = this.ChartBorder.GetHeightEx() * (value - this.HorizontalMin) / (this.HorizontalMax - this.HorizontalMin); return this.ChartBorder.GetBottomEx() - height; } //Y刻度画在内部 this.DrawInsideHorizontal = function () { if (this.IsHScreen === true) return; //横屏不画 if (this.IsMinSize) return; if (this.IsShowYText[0] === false && this.IsShowYText[1] === false) return; var left = this.ChartBorder.GetLeft(); var right = this.ChartBorder.GetRight(); var bottom = this.ChartBorder.GetBottom(); var top = this.ChartBorder.GetTopTitle(); var borderRight = this.ChartBorder.Right; var borderLeft = this.ChartBorder.Left; var titleHeight = this.ChartBorder.TitleHeight; if (borderLeft >= 10) return; if ((borderLeft < 10 && this.IsShowYText[0] === true) || (borderRight < 10 && this.IsShowYText[1] === true)) { var yPrev = null; //上一个坐标y的值 for (var i = this.HorizontalInfo.length - 1; i >= 0; --i) //从上往下画分割线 { var item = this.HorizontalInfo[i]; if (!item) continue; var y = this.GetYFromData(item.Value); if (y != null && yPrev !=null && Math.abs(y - yPrev) < this.MinYDistance) continue; //两个坐标在近了 就不画了 //坐标信息 左边 间距小于10 画在内部 if (item.Message[0] != null && borderLeft < 10 && this.IsShowYText[0] === true) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.fillStyle = item.TextColor; this.Canvas.textAlign = "left"; var yText=y; if (y >= bottom - 2) { this.Canvas.textBaseline = 'bottom'; } else if (y <= top + 2) { this.Canvas.textBaseline = 'top'; yText+=this.YTextTopOffset; } else { if (this.YTextBaseline==1) this.Canvas.textBaseline = "bottom"; else this.Canvas.textBaseline = "middle"; } var textObj = { X: left, Y: yText, Text: { BaseLine: this.Canvas.textBaseline, Font: this.Canvas.font, Value: item.Message[0] } }; if (!this.IsOverlayMaxMin || !this.IsOverlayMaxMin(textObj)) this.Canvas.fillText(item.Message[0], left + 1, yText); } if (item.Message[1] != null && borderRight < 10 && this.IsShowYText[1] === true) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.fillStyle = item.TextColor; this.Canvas.textAlign = "right"; var yText=y; if (y >= bottom - 2) { this.Canvas.textBaseline = 'bottom'; } else if (y <= top + 2) { this.Canvas.textBaseline = 'top'; yText+=this.YTextTopOffset; } else { if (this.YTextBaseline==1) this.Canvas.textBaseline = "bottom"; else this.Canvas.textBaseline = "middle"; } var textWidth = this.Canvas.measureText(item.Message[1]).width; var textObj = { X: right - textWidth, Y: yText, Text: { BaseLine: this.Canvas.textBaseline, TextAlign: this.Canvas.textAlign, Font: this.Canvas.font, Value: item.Message[1] } }; if (!this.IsOverlayMaxMin || !this.IsOverlayMaxMin(textObj)) this.Canvas.fillText(item.Message[1], right - 1, yText); } yPrev = y; } } } //画Y轴 this.DrawHorizontal = function () { var left = this.ChartBorder.GetLeft(); var right = this.ChartBorder.GetRight(); var bottom = this.ChartBorder.GetBottom(); var top = this.ChartBorder.GetTopTitle(); var borderRight = this.ChartBorder.Right; var borderLeft = this.ChartBorder.Left; var titleHeight = this.ChartBorder.TitleHeight; this.Canvas.save(); var yPrev = null; //上一个坐标y的值 for (var i = this.HorizontalInfo.length - 1; i >= 0; --i) //从上往下画分割线 { var item = this.HorizontalInfo[i]; var y = this.GetYFromData(item.Value); if (y != null && yPrev != null && Math.abs(y - yPrev) 0) { this.Canvas.strokeStyle = item.LineColor; if(g_JSChartResource.FrameYLineDash) { this.Canvas.setLineDash(g_JSChartResource.FrameYLineDash); //虚线 this.Canvas.beginPath(); this.Canvas.moveTo(left, yFixed); this.Canvas.lineTo(right, yFixed); this.Canvas.stroke(); this.Canvas.setLineDash([]); } else { this.Canvas.beginPath(); this.Canvas.moveTo(left, yFixed); this.Canvas.lineTo(right, yFixed); this.Canvas.stroke(); } } } var yText=y; if (y >= bottom - 2) { this.Canvas.textBaseline = 'bottom'; } else if (y <= top + 2) { this.Canvas.textBaseline = 'top'; yText+=this.YTextTopOffset; } else { this.Canvas.textBaseline = "middle"; } //坐标信息 左边 间距小于10 不画坐标 this.Canvas.fillStyle = item.TextColor; this.Canvas.strokeStyle = item.TextColor; if (item.Message[0] != null && borderLeft > 10 && this.IsShowYText[0] === true) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.textAlign = "right"; this.Canvas.fillText(item.Message[0], left - 2, yText); } //坐标信息 右边 间距小于10 不画坐标 if (item.Message[1] != null && borderRight > 10 && this.IsShowYText[1] === true) { if (item.Font != null) this.Canvas.font = item.Font; var xText=right; if (item.LineType==3) { var lineLength=this.ShortYLineLength; this.Canvas.beginPath(); this.Canvas.moveTo(xText,yFixed); this.Canvas.lineTo(xText+lineLength,yFixed); this.Canvas.stroke(); xText+=lineLength; } this.Canvas.textAlign = "left"; this.Canvas.fillText(item.Message[1], xText + 2, yText); } yPrev = y; } this.Canvas.restore(); } this.GetXFromIndex = function (index) { var count = this.XPointCount; if (count == 1) { if (index == 0) return this.ChartBorder.GetLeft(); else return this.ChartBorder.GetRight(); } else if (count <= 0) { return this.ChartBorder.GetLeft(); } else if (index >= count) { return this.ChartBorder.GetRight(); } else { var offset = this.ChartBorder.GetLeft() + this.ChartBorder.GetWidth() * index / count; return offset; } } //画X轴 this.DrawVertical = function () { var top = this.ChartBorder.GetTopTitle(); var bottom = this.ChartBorder.GetBottom(); var right = this.ChartBorder.GetRight(); if (this.ChartBorder.Bottom<=5) return; //高度不够 不显示 var yText = bottom; if (this.XMessageAlign == 'bottom') yText = this.ChartBorder.GetChartHeight(); else this.XMessageAlign = 'top'; var xPrev = null; //上一个坐标x的值 let xPrevTextRight = null; for (var i in this.VerticalInfo) { var x = this.GetXFromIndex(this.VerticalInfo[i].Value); if (x > right) break; if (xPrev != null && Math.abs(x - xPrev) < this.MinXDistance) continue; var item=this.VerticalInfo[i]; var xFixed=ToFixedPoint(x); if (this.IsShowXLine && item.LineType > 0) { if (item.LineType==2) { this.Canvas.strokeStyle = item.LineColor; this.Canvas.setLineDash([5,5]); this.Canvas.beginPath(); this.Canvas.moveTo(xFixed, top); this.Canvas.lineTo(xFixed, bottom); this.Canvas.stroke(); this.Canvas.setLineDash([]); } else if (item.LineType==3) { } else if (item.LineType>0) { if(g_JSChartResource.FrameXLineDash) { this.Canvas.strokeStyle = item.LineColor; this.Canvas.beginPath(); this.Canvas.setLineDash(g_JSChartResource.FrameXLineDash); this.Canvas.moveTo(xFixed, top); this.Canvas.lineTo(xFixed, bottom); this.Canvas.stroke(); this.Canvas.setLineDash([]); } else { this.Canvas.strokeStyle = item.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(xFixed, top); this.Canvas.lineTo(xFixed, bottom); this.Canvas.stroke(); } } } if (this.VerticalInfo[i].Message[0] != null && this.ChartBorder.Bottom > 5) { let xTextRight = null; let xTextLeft = null; if (this.VerticalInfo[i].Font != null) this.Canvas.font = this.VerticalInfo[i].Font; this.Canvas.fillStyle=item.TextColor; this.Canvas.strokeStyle=item.TextColor; var testWidth = this.Canvas.measureText(this.VerticalInfo[i].Message[0]).width; if (x < testWidth / 2) { this.Canvas.textAlign = "left"; this.Canvas.textBaseline = this.XMessageAlign; xTextRight = x + testWidth; xTextLeft = x; } else if ((x + testWidth / 2) >= this.ChartBorder.GetChartWidth()) { this.Canvas.textAlign = "right"; this.Canvas.textBaseline = this.XMessageAlign; xTextRight = x + testWidth; xTextLeft = x; } else { this.Canvas.textAlign = "center"; this.Canvas.textBaseline = this.XMessageAlign; xTextRight = x + testWidth / 2; xTextLeft = x - testWidth / 2; } if (xPrevTextRight != null && xPrevTextRight > xTextLeft) continue; var yText=bottom; if (item.LineType==3) { var lineLength=this.ShortXLineLength; this.Canvas.beginPath(); this.Canvas.moveTo(xFixed,yText); this.Canvas.lineTo(xFixed,yText+lineLength); this.Canvas.stroke(); yText+=lineLength+2; } this.Canvas.fillText(this.VerticalInfo[i].Message[0], x, yText + this.XBottomOffset); xPrevTextRight = xTextRight; } xPrev = x; } } this.GetYData = function (y) //Y坐标转y轴数值 { if (y < this.ChartBorder.GetTopEx()) return this.HorizontalMax; if (y > this.ChartBorder.GetBottomEx()) return this.HorizontalMin; return (this.ChartBorder.GetBottomEx() - y) / this.ChartBorder.GetHeightEx() * (this.HorizontalMax - this.HorizontalMin) + this.HorizontalMin; } this.GetXData = function (x) //X坐标转x轴数值 { if (x <= this.ChartBorder.GetLeft()) return 0; if (x >= this.ChartBorder.GetRight()) return this.XPointCount; return (x - this.ChartBorder.GetLeft()) * (this.XPointCount * 1.0 / this.ChartBorder.GetWidth()); } this.DrawCustomItem = function (item) //显示自定义刻度 { //if (this.IsHScreen === true) return; //横屏不画 if (!item.Message[1] && !item.Message[0]) return; if (item.Value > this.HorizontalMax || item.Value < this.HorizontalMin) return; var left = this.ChartBorder.GetLeft(); var right = this.ChartBorder.GetRight(); var bottom = this.ChartBorder.GetBottom(); var top = this.ChartBorder.GetTopTitle(); var borderRight = this.ChartBorder.Right; var borderLeft = this.ChartBorder.Left; var titleHeight = this.ChartBorder.TitleHeight; if (this.IsHScreen) { borderLeft = this.ChartBorder.Top; borderRight = this.ChartBorder.Bottom; top = this.ChartBorder.GetTop(); bottom = this.ChartBorder.GetBottom(); } var textHeight = 18; var y = this.GetYFromData(item.Value); if (item.Message[0]) { if (borderLeft < 10) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.textAlign = "left"; this.Canvas.textBaseline = "middle"; var textWidth = this.Canvas.measureText(item.Message[0]).width + 2; var bgColor = item.LineColor; var rgb = this.RGBToStruct(item.LineColor); if (rgb) bgColor = `rgba(${rgb.R}, ${rgb.G}, ${rgb.B}, ${g_JSChartResource.FrameLatestPrice.BGAlpha})`; //内部刻度 背景增加透明度 this.Canvas.fillStyle = bgColor; if (this.IsHScreen) { var bgTop = top; var textLeft = y - textHeight / 2 - 1; this.Canvas.fillRect(textLeft, bgTop, textHeight, textWidth); this.DrawHScreenText({ X: y, Y: bgTop }, { Text: item.Message[0], Color: item.TextColor, XOffset: 1, YOffset: 2 }); this.DrawLine(bgTop + textWidth, bottom, y, item.LineColor,item.LineType); } else { var bgTop = y - textHeight / 2 - 1; var textLeft = left + 1; this.Canvas.fillRect(textLeft, bgTop, textWidth, textHeight); this.Canvas.fillStyle = item.TextColor; this.Canvas.fillText(item.Message[0], textLeft + 1, y); this.DrawLine(textLeft + textWidth, right, y, item.LineColor,item.LineType); } } else { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.textAlign = "right"; this.Canvas.textBaseline = "middle"; var textWidth = this.Canvas.measureText(item.Message[0]).width + 2; this.Canvas.fillStyle = item.LineColor; if (this.IsHScreen) { var bgTop = top - textWidth; var textLeft = y - textHeight / 2 - 1 ; this.Canvas.fillRect(textLeft, bgTop, textHeight, textWidth); this.DrawHScreenText({ X: y, Y: bgTop }, { Text: item.Message[0], Color: item.TextColor, XOffset: 1, YOffset: 2 }); this.DrawLine(bgTop + textWidth, bottom, y, item.LineColor,item.LineType); } else { var bgTop = y - textHeight / 2 - 1; this.Canvas.fillRect(left - textWidth, bgTop, textWidth, textHeight); this.Canvas.fillStyle = item.TextColor; this.Canvas.fillText(item.Message[0], left - 1, y); this.DrawLine(left, right, y, item.LineColor,item.LineType); } } } else if (item.Message[1]) { if (borderRight < 10) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.textAlign = "left"; this.Canvas.textBaseline = "middle"; var textWidth = this.Canvas.measureText(item.Message[1]).width + 2; var bgColor = item.LineColor; var rgb = this.RGBToStruct(item.LineColor); if (rgb) bgColor = `rgba(${rgb.R}, ${rgb.G}, ${rgb.B}, ${g_JSChartResource.FrameLatestPrice.BGAlpha})`; //内部刻度 背景增加透明度 this.Canvas.fillStyle = bgColor; if (this.IsHScreen) { var bgTop = bottom - textWidth; var textLeft = y - textHeight / 2 - 1; this.Canvas.fillRect(textLeft, bgTop, textHeight, textWidth); this.DrawHScreenText({ X: y, Y: bgTop }, { Text: item.Message[1], Color: item.TextColor, XOffset: 1, YOffset: 2 }); this.DrawLine(top, bgTop, y, item.LineColor,item.LineType); } else { var bgTop = y - textHeight / 2 - 1; var textLeft = right - textWidth; this.Canvas.fillRect(textLeft, bgTop, textWidth, textHeight); this.Canvas.fillStyle = item.TextColor; this.Canvas.fillText(item.Message[1], textLeft + 1, y); this.DrawLine(left, textLeft, y, item.LineColor,item.LineType); } } else { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.textAlign = "left"; this.Canvas.textBaseline = "middle"; var textWidth = this.Canvas.measureText(item.Message[1]).width + 2; this.Canvas.fillStyle = item.LineColor; if (this.IsHScreen) { var bgTop = bottom; var textLeft = y - textHeight / 2 - 1 ; this.Canvas.fillRect(textLeft, bgTop, textHeight, textWidth); this.DrawHScreenText({ X: y, Y: bgTop }, { Text: item.Message[1], Color: item.TextColor, XOffset: 1 , YOffset: 2 }); this.DrawLine(top, bgTop, y, item.LineColor,item.LineType); } else { var bgTop = y - textHeight / 2 - 1; this.Canvas.fillRect(right, bgTop, textWidth, textHeight); this.Canvas.fillStyle = item.TextColor; this.Canvas.fillText(item.Message[1], right + 1, y); this.DrawLine(left, right, y, item.LineColor,item.LineType); } } } } this.DrawLine=function(left, right, y, color, lineType) { if (lineType==-1) return; if (lineType==0) { this.Canvas.strokeStyle = color; this.Canvas.beginPath(); if (this.IsHScreen) { this.Canvas.moveTo(ToFixedPoint(y), left); this.Canvas.lineTo(ToFixedPoint(y), right); } else { this.Canvas.moveTo(left, ToFixedPoint(y)); this.Canvas.lineTo(right, ToFixedPoint(y)); } this.Canvas.stroke(); } else { this.DrawDotLine(left, right, y, color); } } this.DrawDotLine = function (left, right, y, color) { this.Canvas.save(); this.Canvas.strokeStyle = color; this.Canvas.setLineDash([5, 5]); //虚线 this.Canvas.beginPath(); if (this.IsHScreen) { this.Canvas.moveTo(ToFixedPoint(y), left); this.Canvas.lineTo(ToFixedPoint(y), right); } else { this.Canvas.moveTo(left, ToFixedPoint(y)); this.Canvas.lineTo(right, ToFixedPoint(y)); } this.Canvas.stroke(); this.Canvas.restore(); } this.RGBToStruct = function (rgb) { if (/^(rgb|RGB)/.test(rgb)) { var aColor = rgb.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(","); var result = {}; if (aColor.length != 3) return null; result.R = Number(aColor[0]); result.G = Number(aColor[1]); result.B = Number(aColor[2]); return result; } return null; } this.DrawHScreenText = function (center, data) { this.Canvas.textAlign = "left"; this.Canvas.textBaseline = "middle"; this.Canvas.fillStyle = data.Color; this.Canvas.save(); this.Canvas.translate(center.X, center.Y); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(data.Text, data.XOffset, data.YOffset); this.Canvas.restore(); } this.GetScaleTextWidth=function() { var border=this.ChartBorder.GetBorder(); if (this.IsHScreen) { var borderTop = this.ChartBorder.Top; var borderBottom = this.ChartBorder.Bottom; var isDrawLeft=borderTop>10 && this.IsShowYText[0]===true; var isDrawRight=borderBottom>10 && this.IsShowYText[1]===true; } else { var borderRight=this.ChartBorder.Right; var borderLeft=this.ChartBorder.Left; var isDrawLeft=borderLeft>10 && this.IsShowYText[0]===true; var isDrawRight=borderRight>10 && this.IsShowYText[1]===true; } var width={ Left:null, Right:null }; if (!isDrawRight && !isDrawLeft) return width; for(var i=0;i= count) { return this.ChartBorder.GetRight(); } else { var offset = this.ChartBorder.GetLeft() + this.ChartBorder.GetWidth() * index / count; return offset; } } //X坐标转x轴数值 this.GetXData = function (x) { if (x <= this.ChartBorder.GetLeft()) return 0; if (x >= this.ChartBorder.GetRight()) return this.XPointCount; return (x - this.ChartBorder.GetLeft()) * (this.XPointCount * 1.0 / this.ChartBorder.GetWidth()); } this.DrawCustomHorizontal = function () //Y轴刻度定制显示 { if (this.IsMinSize) return; for (var i in this.CustomHorizontalInfo) { var item = this.CustomHorizontalInfo[i]; switch (item.Type) { case 0: case 1: this.DrawCustomItem(item); //自定义刻度 break; } } } } function MinuteHScreenFrame() { this.newMethod = MinuteFrame; //派生 this.newMethod(); delete this.newMethod; this.ClassName='MinuteHScreenFrame'; this.IsHScreen = true; //是否是横屏 //画标题背景色 this.DrawTitleBG = function () { /* if (this.ChartBorder.TitleHeight <= 0) return; var left = ToFixedPoint(this.ChartBorder.GetRightEx()); var top = ToFixedPoint(this.ChartBorder.GetTop()); var bottom = ToFixedPoint(this.ChartBorder.GetBottom()); var width = this.ChartBorder.TitleHeight; var height = bottom - top; this.Canvas.fillStyle = this.TitleBGColor; this.Canvas.fillRect(left, top, width, height); */ } this.DrawInsideHorizontal = function () { } //Y坐标转y轴数值 this.GetYData = function (x) { if (x < this.ChartBorder.GetLeftEx()) return this.HorizontalMin; if (x > this.ChartBorder.GetRightEx()) return this.HorizontalMax; return (x - this.ChartBorder.GetLeftEx()) / this.ChartBorder.GetWidthEx() * (this.HorizontalMax - this.HorizontalMin) + this.HorizontalMin; } //X坐标转x轴数值 this.GetXData = function (y) { if (y <= this.ChartBorder.GetTop()) return 0; if (y >= this.ChartBorder.GetBottom()) return this.XPointCount; var count=this.XPointCount-1; return (y - this.ChartBorder.GetTop()) * (count * 1.0 / this.ChartBorder.GetHeight()); } this.GetXFromIndex = function (index) { var count = this.XPointCount - 1; if (count == 1) { if (index == 0) return this.ChartBorder.GetTop(); else return this.ChartBorder.GetBottom(); } else if (count <= 0) { return this.ChartBorder.GetTop(); } else if (index >= count) { return this.ChartBorder.GetBottom(); } else { var offset = this.ChartBorder.GetTop() + this.ChartBorder.GetHeight() * index / count; return offset; } } this.GetYFromData = function (value) { if (value <= this.HorizontalMin) return this.ChartBorder.GetLeft(); if (value >= this.HorizontalMax) return this.ChartBorder.GetRightEx(); var width = this.ChartBorder.GetWidthEx() * (value - this.HorizontalMin) / (this.HorizontalMax - this.HorizontalMin); return this.ChartBorder.GetLeft() + width; } //画Y轴 this.DrawHorizontal = function () { var top = this.ChartBorder.GetTop(); var bottom = this.ChartBorder.GetBottom(); var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var borderTop = this.ChartBorder.Top; var borderBottom = this.ChartBorder.Bottom; var yPrev = null; //上一个坐标y的值 for (var i = this.HorizontalInfo.length - 1; i >= 0; --i) //从左往右画分割线 { var item = this.HorizontalInfo[i]; var y = this.GetYFromData(item.Value); if (y != null && Math.abs(y - yPrev) < this.MinYDistance) continue; //两个坐标在近了 就不画了 this.Canvas.strokeStyle = item.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(y), top); this.Canvas.lineTo(ToFixedPoint(y), bottom); this.Canvas.stroke(); if (y >= right - 2) { this.Canvas.textBaseline = 'top'; y = right; } else if (y <= left + 2) { this.Canvas.textBaseline = 'bottom'; y=left; if (y != null && Math.abs(y - yPrev) < 2*this.MinYDistance) continue; //两个坐标在近了 就不画了 } else { this.Canvas.textBaseline = "middle"; } //坐标信息 左边 间距小于10 不画坐标 if (item.Message[0] != null && borderTop > 10) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.fillStyle = item.TextColor; this.Canvas.textAlign = "right"; //this.Canvas.textBaseline = "middle"; var xText = y, yText = top; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(item.Message[0], -2, 0); this.Canvas.restore(); } //坐标信息 右边 间距小于10 不画坐标 if (item.Message[1] != null && borderBottom > 10) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.fillStyle = item.TextColor; this.Canvas.textAlign = "left"; //this.Canvas.textBaseline = "middle"; var xText = y, yText = bottom; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(item.Message[1], 2, 0); this.Canvas.restore(); } yPrev = y; } } //画X轴 this.DrawVertical = function () { var left = this.ChartBorder.GetLeft(); var right = this.ChartBorder.GetRightEx(); var bottom = this.ChartBorder.GetBottom(); var xPrev = null; //上一个坐标x的值 for (var i in this.VerticalInfo) { var x = this.GetXFromIndex(this.VerticalInfo[i].Value); if (x > bottom) break; if (xPrev != null && Math.abs(x - xPrev) < this.MinXDistance) continue; this.Canvas.strokeStyle = this.VerticalInfo[i].LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(left, ToFixedPoint(x)); this.Canvas.lineTo(right, ToFixedPoint(x)); this.Canvas.stroke(); if (this.VerticalInfo[i].Message[0] != null) { if (this.VerticalInfo[i].Font != null) this.Canvas.font = this.VerticalInfo[i].Font; this.Canvas.fillStyle = this.VerticalInfo[i].TextColor; var testWidth = this.Canvas.measureText(this.VerticalInfo[i].Message[0]).width; if (x < testWidth / 2) { this.Canvas.textAlign = "left"; this.Canvas.textBaseline = "top"; } else if ((x + testWidth / 2) >= this.ChartBorder.GetChartHeight()) { this.Canvas.textAlign = "right"; this.Canvas.textBaseline = "top"; } else { this.Canvas.textAlign = "center"; this.Canvas.textBaseline = "top"; } var xText = left, yText = x; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(this.VerticalInfo[i].Message[0], 0, 0); this.Canvas.restore(); } xPrev = x; } } } //K线框架 function KLineFrame() { this.newMethod = AverageWidthFrame; //派生 this.newMethod(); delete this.newMethod; this.ClassName='KLineFrame'; this.ToolbarID = Guid(); //工具条Div id this.ModifyIndex = true; //是否显示'改参数'菜单 this.ChangeIndex = true; //是否显示'换指标'菜单 this.CustomHorizontalInfo = []; this.LastCalculateStatus = { Width: 0, XPointCount: 0 }; //最后一次计算宽度的状态 //定制X轴刻度 //Type:0, Date:, Time: , Name:名字, Line:{ Color:线段颜色, Type:线段类型 0 直线 1 虚线 } //Type: 1, Space: 第几个空白间距, Name:名字, Line: { Color: 线段颜色, Type: 线段类型 0 直线 1 虚线 } this.CustomVerticalInfo = []; this.DrawCustomVerticalEvent; this.RightSpaceCount = 0; this.DrawFrame = function () { if (this.IsMinSize) return; this.SplitXYCoordinate(); if (this.SizeChange == true) this.CalculateDataWidth(); if (this.DrawOtherChart) this.DrawOtherChart(); this.DrawTitleBG(); this.DrawHorizontal(); this.DrawVertical(); } this.GetXFromIndex = function (index) { if (index < 0) index = 0; if (index > this.xPointCount - 1) index = this.xPointCount - 1; var offset = this.ChartBorder.GetLeft() + g_JSChartResource.FrameLeftMargin + this.DistanceWidth / 2 + this.DataWidth / 2; for (var i = 1; i <= index; ++i) { offset += this.DistanceWidth + this.DataWidth; } return offset; } //X坐标转x轴数值 this.GetXData = function (x) { if (x <= this.ChartBorder.GetLeft()) return 0; if (x >= this.ChartBorder.GetRight()) return this.XPointCount-1; var left=this.ChartBorder.GetLeft()+g_JSChartResource.FrameLeftMargin; var right=this.ChartBorder.GetRight()-g_JSChartResource.FrameRightMargin; var distanceWidth = this.DistanceWidth; var dataWidth = this.DataWidth; var index = 0; var xPoint = left + distanceWidth/2 + dataWidth + distanceWidth; while (xPoint < right && index < 10000 && index+1 x) break; xPoint += (dataWidth + distanceWidth); ++index; } //var test=(x-this.ChartBorder.GetLeft())*(this.XPointCount*1.0/this.ChartBorder.GetWidth()); return index; } this.DrawCustomHorizontal = function () //Y轴刻度定制显示 { if (this.IsMinSize) return; for (var i in this.CustomHorizontalInfo) { var item = this.CustomHorizontalInfo[i]; switch (item.Type) { case 0: //最新价格刻度 case 1: //固定价格刻度 this.DrawCustomItem(item); break; } } } this.DrawCustomVerticalItem = function (item) { this.Canvas.save(); if (item.Data.Line.Type == 1) this.Canvas.setLineDash([5, 5]); //虚线 this.Canvas.strokeStyle = item.Data.Line.Color; this.Canvas.beginPath(); if (item.IsHScreen) { this.Canvas.moveTo(item.Top, ToFixedPoint(item.X)); this.Canvas.lineTo(item.Bottom, ToFixedPoint(item.X)); } else { this.Canvas.moveTo(ToFixedPoint(item.X), item.Top); this.Canvas.lineTo(ToFixedPoint(item.X), item.Bottom); } this.Canvas.stroke(); this.Canvas.restore(); } this.DrawCustomVertical = function () //X轴定制刻度显示 { if (!this.CustomVerticalInfo) return; if (this.CustomVerticalInfo.length <= 0) return; if (!this.Data) return; var isHScreen = this.IsHScreen; var top = this.ChartBorder.GetTopEx(); var bottom = this.ChartBorder.GetBottomEx(); var dataWidth = this.DataWidth; var distanceWidth = this.DistanceWidth; var xOffset = this.ChartBorder.GetLeft() + distanceWidth / 2.0 + 2.0; if (isHScreen) { xOffset = this.ChartBorder.GetTop() + distanceWidth / 2.0 + 2.0; top = this.ChartBorder.GetLeftEx(); bottom = this.ChartBorder.GetRightEx(); } var j = 0; for (var i = this.Data.DataOffset; i < this.Data.Data.length && j < this.XPointCount; ++i, ++j, xOffset += (dataWidth + distanceWidth)) { var kItem = this.Data.Data[i]; for (var k in this.CustomVerticalInfo) { var item = this.CustomVerticalInfo[k]; if (item.Type != 0) continue; if (IFrameSplitOperator.IsNumber(item.Time)) { if (kItem.Date != item.Date || kItem.Time != item.Time) continue; } else { if (kItem.Date != item.Date) continue; } var left = xOffset; var right = xOffset + dataWidth; var x = left + (right - left) / 2; var DrawData = { X: x, Top: top, Bottom: bottom, Data: item, IsHScreen: isHScreen }; this.DrawCustomVerticalItem(DrawData); if (this.DrawCustomVerticalEvent) this.DrawCustomVerticalEvent.Callback(this.DrawCustomVerticalEvent, DrawData, this); break; } } for (var i = 1; j < this.XPointCount; ++i, ++j, xOffset += (dataWidth + distanceWidth)) { for (var k in this.CustomVerticalInfo) { var item = this.CustomVerticalInfo[k]; if (item.Type != 1) continue; if (item.Space != i) continue; var left = xOffset; var right = xOffset + dataWidth; var x = left + (right - left) / 2; var DrawData = { X: x, Top: top, Bottom: bottom, Data: item, IsHScreen: isHScreen }; this.DrawCustomVerticalItem(DrawData); if (this.DrawCustomVerticalEvent) this.DrawCustomVerticalEvent.Callback(this.DrawCustomVerticalEvent, DrawData, this); break; } } } this.CalculateDataWidth = function () //计算数据宽度 { if (this.XPointCount < 2) return; var width = this.GetFrameWidth() - g_JSChartResource.FrameMargin; //预留4个像素 防止最后1个柱子不够画 if (this.ZoomIndex>=0 && this.LastCalculateStatus.Width==width && this.LastCalculateStatus.XPointCount==this.XPointCount) //宽度没变 尝试使用原来的柱子宽度 { var caclWidth=(this.DistanceWidth/2+g_JSChartResource.FrameLeftMargin)+(this.DataWidth + this.DistanceWidth)*(this.XPointCount-1); var caclWidth2=(this.DataWidth + this.DistanceWidth) * this.XPointCount; if (caclWidth<= width) //当前的柱子宽度够用 就不调整了 return; } this.LastCalculateStatus.Width=width; this.LastCalculateStatus.XPointCount=this.XPointCount; for (var i = 0; i < ZOOM_SEED.length; ++i) { let barWidth = ZOOM_SEED[i][0]; //数据宽度 let distanceWidth = ZOOM_SEED[i][1]; //间距宽度 if ((ZOOM_SEED[i][0] + ZOOM_SEED[i][1]) * this.XPointCount < width) { this.ZoomIndex = i; this.DataWidth = ZOOM_SEED[i][0]; this.DistanceWidth = ZOOM_SEED[i][1]; this.TrimKLineDataWidth(width); JSConsole.Chart.Log(`[KLineFrame::CalculateDataWidth] ZoomIndex=${this.ZoomIndex} DataWidth=${this.DataWidth} DistanceWidth=${this.DistanceWidth}` ); return; } } //太多了 就平均分了 this.ZoomIndex = ZOOM_SEED.length - 1; this.DataWidth = width / this.XPointCount; this.DistanceWidth = 0; } this.OnSize=function(obj) { var width=this.GetFrameWidth()-g_JSChartResource.FrameMargin; var xPointCount=0; var y=this.DistanceWidth/2+g_JSChartResource.FrameLeftMargin+(this.DataWidth+this.DistanceWidth); for(;y width) { this.DistanceWidth -= 0.01; break; } this.DistanceWidth += 0.01; } } else { while (true) { if ((this.DistanceWidth + this.DataWidth) * this.XPointCount + this.DistanceWidth > width) { this.DataWidth -= 0.01; break; } this.DataWidth += 0.01; } } } this.IsOverlayMaxMin = function (obj) //当前坐标信息 是否覆盖最大 最小值输出 { if (!this.ChartKLine) return false; if (!this.ChartKLine.Max || !this.ChartKLine.Min) return false; var textWidth = this.Canvas.measureText(obj.Text.Value).width + 4; //刻度文字宽度 var max = this.ChartKLine.Max, min = this.ChartKLine.Min; var isOverlayMax = false, isOverlayMin = false; const textHeight = 20; //字体高度 if (max.X >= obj.X && max.X <= obj.X + textWidth) { var y1 = max.Y + textHeight, y2 = max.Y - textHeight; if ((y1 >= obj.Y - textHeight && y1 <= obj.Y + textHeight) || (y2 >= obj.Y - textHeight && y2 <= obj.Y + textHeight)) isOverlayMax = true; } if (isOverlayMax == true) return true; if (min.X >= obj.X && min.X <= obj.X + textWidth) //最小值X 坐标不在 刻度文字范围内 { var y1 = min.Y + textHeight, y2 = min.Y - textHeight; if ((y1 >= obj.Y - textHeight && y1 <= obj.Y + textHeight) || (y2 >= obj.Y - textHeight && y2 <= obj.Y + textHeight)) isOverlayMin = true; } return isOverlayMax || isOverlayMin; } //分割x,y轴坐标信息 this.SplitXYCoordinate = function () { if (this.XYSplit == false) return; if (this.YSplitOperator != null) this.YSplitOperator.Operator(); if (this.XSplitOperator != null) this.XSplitOperator.Operator(); } this.CalculateCount = function (zoomIndex) { var width = this.GetFrameWidth() - g_JSChartResource.FrameMargin; return parseInt(width / (ZOOM_SEED[zoomIndex][0] + ZOOM_SEED[zoomIndex][1])); } this.ZoomUp = function (cursorIndex) { if (this.ZoomIndex <= 0) return false; if (this.Data.DataOffset < 0) return false; var dataCount = this.Data.Data.length; var maxDataCount = dataCount + this.RightSpaceCount; var rightSpaceCount = 0; var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1; //最右边的数据索引 var lastCursorIndex = this.Data.DataOffset + cursorIndex.Index; if (lastDataIndex >= dataCount) { rightSpaceCount = lastDataIndex - (this.Data.Data.length - 1); //计算右边预留空间 lastDataIndex = this.Data.Data.length - 1; if (rightSpaceCount > this.RightSpaceCount) rightSpaceCount = this.RightSpaceCount; } var xPointCount = this.CalculateCount(this.ZoomIndex-1); --this.ZoomIndex; this.XPointCount = xPointCount; if (xPointCount >= maxDataCount) { xPointCount = maxDataCount; this.XPointCount = xPointCount; this.Data.DataOffset = 0; } else { this.XPointCount = xPointCount; this.Data.DataOffset = lastDataIndex - (this.XPointCount - rightSpaceCount) + 1; } this.DataWidth = ZOOM_SEED[this.ZoomIndex][0]; this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1]; var width = this.GetFrameWidth() - g_JSChartResource.FrameMargin; this.TrimKLineDataWidth(width); this.LastCalculateStatus.XPointCount = this.XPointCount; cursorIndex.Index = lastCursorIndex - this.Data.DataOffset; return true; } this.ZoomDown = function (cursorIndex) { if (this.ZoomIndex + 1 >= ZOOM_SEED.length) return false; if (this.Data.DataOffset < 0) return false; var dataCount = this.Data.Data.length; var maxDataCount = dataCount + this.RightSpaceCount; if (this.XPointCount >= dataCount) return false; var rightSpaceCount = 0; var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1; //最右边的数据索引 if (lastDataIndex >= this.Data.Data.length) { rightSpaceCount = lastDataIndex - (this.Data.Data.length - 1); //计算右边预留空间 lastDataIndex = this.Data.Data.length - 1; if (rightSpaceCount > this.RightSpaceCount) rightSpaceCount = this.RightSpaceCount; } var xPointCount = this.CalculateCount(this.ZoomIndex + 1); var lastCursorIndex = this.Data.DataOffset + cursorIndex.Index; ++this.ZoomIndex; if (xPointCount >= maxDataCount) { xPointCount = maxDataCount; this.XPointCount = xPointCount; this.Data.DataOffset = 0; } else { this.XPointCount = xPointCount; this.Data.DataOffset = lastDataIndex - (this.XPointCount - rightSpaceCount) + 1; } this.DataWidth = ZOOM_SEED[this.ZoomIndex][0]; this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1]; var width = this.GetFrameWidth() - g_JSChartResource.FrameMargin; this.TrimKLineDataWidth(width); this.LastCalculateStatus.XPointCount = this.XPointCount; cursorIndex.Index = lastCursorIndex - this.Data.DataOffset; return true; } this.GetFrameWidth = function () { if (this.IsHScreen) return this.ChartBorder.GetHeight(); return this.ChartBorder.GetWidth(); } } //K线横屏框架 function KLineHScreenFrame() { this.newMethod = KLineFrame; //派生 this.newMethod(); delete this.newMethod; this.ClassName='KLineHScreenFrame'; this.IsHScreen = true; //是否是横屏 this.DrawInsideHorizontal = function () { if (this.IsMinSize) return; if (this.IsShowYText[0] === false && this.IsShowYText[1] === false) return; var left = this.ChartBorder.GetLeft(); var right = this.ChartBorder.GetRightEx(); var top = this.ChartBorder.GetTop(); var bottom = this.ChartBorder.GetBottom(); var borderTop = this.ChartBorder.Top; var borderBottom = this.ChartBorder.Bottom; var titleHeight = this.ChartBorder.TitleHeight; var pixelTatio = 1; var isDrawLeft = (borderTop < 10 * pixelTatio || this.YTextPosition[0] == 2) && this.IsShowYText[0] === true; var isDrawRight = (borderBottom < 10 * pixelTatio || this.YTextPosition[1] == 2) && this.IsShowYText[1] === true; if (isDrawLeft || isDrawRight) { var yPrev = null; //上一个坐标y的值 for (var i = this.HorizontalInfo.length - 1; i >= 0; --i) //从上往下画分割线 { var item = this.HorizontalInfo[i]; var y = this.GetYFromData(item.Value); if (y != null && yPrev != null && Math.abs(y - yPrev) < this.MinYDistance) continue; //两个坐标在近了 就不画了 //坐标信息 左边 间距小于10 画在内部 if (item.Message[0] != null && isDrawLeft) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.fillStyle = item.TextColor; this.Canvas.textAlign = "left"; if (y >= right - 2) this.Canvas.textBaseline = 'top'; else if (y <= left + 2) this.Canvas.textBaseline = 'bottom'; else this.Canvas.textBaseline = "middle"; var textObj = { X: left, Y: y, Text: { BaseLine: this.Canvas.textBaseline, TextAlign: this.Canvas.textAlign, Font: this.Canvas.font, Value: item.Message[0] } }; var xText = y, yText = top; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(item.Message[0], -2, 0); this.Canvas.restore(); } if (item.Message[1] != null && isDrawRight) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.fillStyle = item.TextColor; this.Canvas.textAlign = "right"; if (y >= right - 2) this.Canvas.textBaseline = 'top'; else if (y <= left + 2) this.Canvas.textBaseline = 'bottom'; else this.Canvas.textBaseline = "middle"; var textWidth = this.Canvas.measureText(item.Message[1]).width; var textObj = { X: right - textWidth, Y: y, Text: { BaseLine: this.Canvas.textBaseline, TextAlign: this.Canvas.textAlign, Font: this.Canvas.font, Value: item.Message[1] } }; var xText = y, yText = bottom; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(item.Message[1], 2, 0); this.Canvas.restore(); } yPrev = y; } } } //画标题背景色 this.DrawTitleBG = function () { /* if (this.ChartBorder.TitleHeight <= 0) return; var left = ToFixedPoint(this.ChartBorder.GetRightEx()); var top = ToFixedPoint(this.ChartBorder.GetTop()); var bottom = ToFixedPoint(this.ChartBorder.GetBottom()); var width = this.ChartBorder.TitleHeight; var height = bottom - top; this.Canvas.fillStyle = this.TitleBGColor; this.Canvas.fillRect(left, top, width, height); */ } this.GetYFromData = function (value) { if (value <= this.HorizontalMin) return this.ChartBorder.GetLeftEx(); if (value >= this.HorizontalMax) return this.ChartBorder.GetRightEx(); var width = this.ChartBorder.GetWidthEx() * (value - this.HorizontalMin) / (this.HorizontalMax - this.HorizontalMin); return this.ChartBorder.GetLeftEx() + width; } //画Y轴 this.DrawHorizontal = function () { var top = this.ChartBorder.GetTop(); var bottom = this.ChartBorder.GetBottom(); var borderTop = this.ChartBorder.Top; var borderBottom = this.ChartBorder.Bottom; var left=this.ChartBorder.GetLeft(); var yPrev = null; //上一个坐标y的值 for (var i = this.HorizontalInfo.length - 1; i >= 0; --i) //从左往右画分割线 { var item = this.HorizontalInfo[i]; var y = this.GetYFromData(item.Value); if (y != null && Math.abs(y - yPrev) < 15) continue; //两个坐标在近了 就不画了 if (y!=left) { if (item.LineType==2) { this.Canvas.strokeStyle = item.LineColor; this.Canvas.setLineDash([5,5]); //虚线 this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(y),top); this.Canvas.lineTo(ToFixedPoint(y),bottom); this.Canvas.stroke(); this.Canvas.setLineDash([]); } else if (item.LineType>0) { this.Canvas.strokeStyle = item.LineColor; if (g_JSChartResource.FrameYLineDash) { this.Canvas.setLineDash(g_JSChartResource.FrameYLineDash); //虚线 this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(y),top); this.Canvas.lineTo(ToFixedPoint(y),bottom); this.Canvas.stroke(); this.Canvas.setLineDash([]); } else { this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(y), top); this.Canvas.lineTo(ToFixedPoint(y), bottom); this.Canvas.stroke(); } } } //坐标信息 左边 间距小于10 不画坐标 if (item.Message[0] != null && borderTop > 10) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.fillStyle = item.TextColor; this.Canvas.textAlign = "right"; this.Canvas.textBaseline = "middle"; var xText = y, yText = top; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(item.Message[0], -2, 0); this.Canvas.restore(); } //坐标信息 右边 间距小于10 不画坐标 if (item.Message[1] != null && borderBottom > 10) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.fillStyle = item.TextColor; this.Canvas.textAlign = "left"; this.Canvas.textBaseline = "middle"; var xText = y, yText = bottom; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(item.Message[1], 2, 0); this.Canvas.restore(); } yPrev = y; } } this.GetXFromIndex = function (index) { if (index < 0) index = 0; if (index > this.xPointCount - 1) index = this.xPointCount - 1; var offset = this.ChartBorder.GetTop() + g_JSChartResource.FrameLeftMargin + this.DistanceWidth / 2 + this.DataWidth / 2; for (var i = 1; i <= index; ++i) { offset += this.DistanceWidth + this.DataWidth; } return offset; } //画X轴 this.DrawVertical = function () { var left = this.ChartBorder.GetLeft(); var right = this.ChartBorder.GetRightTitle(); var bottom = this.ChartBorder.GetBottom(); var xPrev = null; //上一个坐标x的值 for (var i in this.VerticalInfo) { var x = this.GetXFromIndex(this.VerticalInfo[i].Value); if (x >= bottom) break; if (xPrev != null && Math.abs(x - xPrev) < 80) continue; var item=this.VerticalInfo[i]; if (item.LineType==2) { this.Canvas.setLineDash([5,5]); this.Canvas.beginPath(); this.Canvas.moveTo(left, ToFixedPoint(x)); this.Canvas.lineTo(right, ToFixedPoint(x)); this.Canvas.stroke(); this.Canvas.setLineDash([]); } else if (item.LineType>0) { this.Canvas.strokeStyle = item.LineColor; if (g_JSChartResource.FrameXLineDash) { this.Canvas.setLineDash(g_JSChartResource.FrameXLineDash); this.Canvas.beginPath(); this.Canvas.moveTo(left, ToFixedPoint(x)); this.Canvas.lineTo(right, ToFixedPoint(x)); this.Canvas.stroke(); this.Canvas.setLineDash([]); } else { this.Canvas.beginPath(); this.Canvas.moveTo(left, ToFixedPoint(x)); this.Canvas.lineTo(right, ToFixedPoint(x)); this.Canvas.stroke(); } } if (this.VerticalInfo[i].Message[0] != null) { if (this.VerticalInfo[i].Font != null) this.Canvas.font = this.VerticalInfo[i].Font; this.Canvas.fillStyle = this.VerticalInfo[i].TextColor; var testWidth = this.Canvas.measureText(this.VerticalInfo[i].Message[0]).width; if (x < testWidth / 2) { this.Canvas.textAlign = "left"; this.Canvas.textBaseline = "top"; } else { this.Canvas.textAlign = "center"; this.Canvas.textBaseline = "top"; } var xText = left, yText = x; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(this.VerticalInfo[i].Message[0], 0, this.XBottomOffset); this.Canvas.restore(); } xPrev = x; } } //Y坐标转y轴数值 this.GetYData = function (x) { if (x < this.ChartBorder.GetLeftEx()) return this.HorizontalMin; if (x > this.ChartBorder.GetRightEx()) return this.HorizontalMax; return (x - this.ChartBorder.GetLeftEx()) / this.ChartBorder.GetWidthEx() * (this.HorizontalMax - this.HorizontalMin) + this.HorizontalMin; } //X坐标转x轴数值 this.GetXData = function (y) { if (y <= this.ChartBorder.GetTop()) return 0; if (y >= this.ChartBorder.GetBottom()) return this.XPointCount-1; var distanceWidth=this.DistanceWidth; var dataWidth=this.DataWidth; var left=this.ChartBorder.GetTop()+g_JSChartResource.FrameLeftMargin; var right=this.ChartBorder.GetBottom()-g_JSChartResource.FrameRightMargin; var index=0; var xPoint=left+distanceWidth/2+dataWidth+distanceWidth; while(xPoint=y) break; xPoint+=(dataWidth+distanceWidth); ++index; } return index; } } function SubFrameItem() { this.Frame; this.Height; } //行情框架 function HQTradeFrame() { this.ClassName='HQTradeFrame'; this.SubFrame = new Array(); //SubFrameItem 数组 this.SizeChange = true; //大小是否改变 this.ChartBorder; this.Canvas; //画布 this.ScreenImagePath; //截图路径 this.ScreenImageData=null; //截图数据 this.Data; //主数据 this.Position; //画布的位置 this.SizeChange = true; this.SnapshotID=0; this.CurrentSnapshotID=0; this.SnapshotStatus=0; //0空闲 1工作 this.AutoLeftBorder=null; //{ Blank:10 留白宽度, MinWidth:最小宽度 } this.AutoRightBorder=null; //{ Blank:10 留白宽度, MinWidth:最小宽度 } this.ZoomWindowsInfo=null; //附图指标缩放,备份信息 this.ZoomStartWindowIndex=1; //允许缩放窗口起始位置 this.CalculateChartBorder = function () //计算每个子框架的边框信息 { if (this.SubFrame.length <= 0) return; var top = this.ChartBorder.GetTop(); var height = this.ChartBorder.GetHeight(); var totalHeight = 0; for (var i in this.SubFrame) { var item = this.SubFrame[i]; totalHeight += item.Height; } for (var i in this.SubFrame) { var item = this.SubFrame[i]; item.Frame.ChartBorder.Top = top; item.Frame.ChartBorder.Left = this.ChartBorder.Left; item.Frame.ChartBorder.Right = this.ChartBorder.Right; var frameHeight = height * (item.Height / totalHeight) + top; item.Frame.ChartBorder.Bottom = this.ChartBorder.GetChartHeight() - frameHeight; top = frameHeight; } } this.GetScaleTextWidth=function() { var width={ Left:null, Right:null }; for(var i in this.SubFrame) { var item=this.SubFrame[i]; if (item.Height<=0) continue; var frame=item.Frame; if (!frame) continue; if (!frame.XSplitOperator) continue; var maxValue=frame.HorizontalMax; //最大最小要还原 var minValue=frame.HorizontalMin; frame.YSplitOperator.Operator(); var value=frame.GetScaleTextWidth(); frame.HorizontalMax=maxValue; frame.HorizontalMin=minValue; if (value && value.TextWidth) { var widthItem=value.TextWidth; if (IFrameSplitOperator.IsNumber(widthItem.Left)) { if (width.Left==null || width.Leftvalue) value=this.AutoLeftBorder.MinWidth; } if (this.IsHScreen) this.ChartBorder.Top=value; else this.ChartBorder.Left=value; for(var i=0; ivalue) value=this.AutoRightBorder.MinWidth; } if (this.IsHScreen) this.ChartBorder.Bottom=value; else this.ChartBorder.Right=value; for(var i=0; i0) { var minPrice=this.BidPrice[0]; if (price0) { var maxPrice=this.AskPrice[this.AskPrice.length-1]; if (price>maxPrice) { isAskPrice=true; find=maxPrice; } } } if (find==null) return null; var x=this.GetXFromIndex(find); return { X:x, Price:find, IsAsk:isAskPrice }; } this.GetPrice=function(aryPrice, price) { if (!aryPrice || !Array.isArray(aryPrice) || aryPrice.length<=0) return null; if (pricearyPrice[aryPrice.length-1]) return null; var lastPrice=null; for(var i in aryPrice) { var item=aryPrice[i]; if (price==item) { return item; } if (pricexRange.MaxDiffer) differ=xRange.MaxDiffer; xRange.Differ=differ; xRange.Min=xRange.Center-xRange.Differ; xRange.Max=xRange.Center+xRange.Differ; return true; } } //一般的图形框架 function SimpleChartFrame() { this.newMethod = AverageWidthFrame; //派生 this.newMethod(); delete this.newMethod; this.ScreenImageData; //截图 this.Position; //画布的位置 this.IsShowBorder = false; //是否显示边框 this.IsShowVertical = false; //是否显示X轴 this.XFontType = 0; //X轴文本文字类型 this.MaxDistanceWidth = 4; this.BarCount = 0; //多柱子个数 this.Draw = function () { this.DrawFrame(); if (this.IsShowBorder) this.DrawBorder(); this.SizeChange = false; this.XYSplit = false; } this.DrawFrame = function () { if (this.XPointCount > 0) { let dInterval = this.ChartBorder.GetWidth() / (10 * this.XPointCount); //分6份, 数据4 间距2 this.DistanceWidth = 4 * dInterval; this.DataWidth = 6 * dInterval; if (this.DistanceWidth > this.MaxDistanceWidth) { this.DistanceWidth = this.MaxDistanceWidth; dInterval = this.ChartBorder.GetWidth() / this.XPointCount; this.DataWidth = dInterval - this.MaxDistanceWidth; } } this.SplitXYCoordinate(); this.DrawHorizontal(); this.DrawVertical(); } this.GetXFromIndex = function (index) { if (index < 0) index = 0; if (index > this.xPointCount - 1) index = this.xPointCount - 1; var offset = this.ChartBorder.GetLeft() + 2 + this.DistanceWidth / 2 + this.DataWidth / 2; for (var i = 1; i <= index; ++i) { offset += this.DistanceWidth + this.DataWidth; } return offset; } //分割x,y轴坐标信息 this.SplitXYCoordinate = function () { if (this.XYSplit == false) return; if (this.YSplitOperator != null) this.YSplitOperator.Operator(); if (this.XSplitOperator != null) this.XSplitOperator.Operator(); } //画X轴 this.DrawVertical = function () { var top = this.ChartBorder.GetTopEx(); var bottom = this.ChartBorder.GetBottom(); var right = this.ChartBorder.GetRight(); var xPrev = null; //上一个坐标x的值 for (var i in this.VerticalInfo) { var x = this.GetXFromIndex(this.VerticalInfo[i].Value); if (x >= right) break; if (this.XFontType == 1) { if (xPrev != null && Math.abs(x - xPrev) < 20) continue; } else { if (xPrev != null && Math.abs(x - xPrev) < 60) continue; } if (this.IsShowVertical) { this.Canvas.strokeStyle = this.VerticalInfo[i].LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(x), top); this.Canvas.lineTo(ToFixedPoint(x), bottom); this.Canvas.stroke(); } if (this.VerticalInfo[i].Message[0] != null) { if (this.VerticalInfo[i].Font != null) this.Canvas.font = this.VerticalInfo[i].Font; this.Canvas.fillStyle = this.VerticalInfo[i].TextColor; var testWidth = this.Canvas.measureText(this.VerticalInfo[i].Message[0]).width; if (x < testWidth / 2) { this.Canvas.textAlign = "left"; this.Canvas.textBaseline = "top"; } else { this.Canvas.textAlign = "center"; this.Canvas.textBaseline = "top"; } if (this.XFontType == 1) { this.Canvas.textAlign = "left"; this.Canvas.textBaseline = "middle"; this.Canvas.save(); this.Canvas.translate(x, bottom); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(this.VerticalInfo[i].Message[0], 2, 0); this.Canvas.restore(); } else this.Canvas.fillText(this.VerticalInfo[i].Message[0], x, bottom); } xPrev = x; } } //图形快照 this.Snapshot = function () { var self = this; var width = this.ChartBorder.GetChartWidth(); var height = this.ChartBorder.GetChartHeight(); JSConsole.Chart.Log('[SimpleChartFrame::Snapshot][ID=' + this.ChartBorder.UIElement.ID + '] invoke canvasToTempFilePath' + '(width=' + width + ',height=' + height + ')'); wx.canvasToTempFilePath({ x: 0, y: 0, width: width, height: height, canvasId: this.ChartBorder.UIElement.ID, success: function (res) { self.ScreenImagePath = res.tempFilePath; JSConsole.Chart.Log(res.tempFilePath) } }) } this.SetSizeChage = function (sizeChange) { this.SizeChange = sizeChange; //画布的位置 this.Position = { X: this.ChartBorder.UIElement.offsetLeft, Y: this.ChartBorder.UIElement.offsetTop, W: this.ChartBorder.UIElement.clientWidth, H: this.ChartBorder.UIElement.clientHeight }; } } //旋转90度坐标 function Rotate90SimpleChartFrame() { this.newMethod = SimpleChartFrame; //派生 this.newMethod(); delete this.newMethod; this.DrawFrame = function () { if (this.XPointCount > 0) { let dInterval = this.ChartBorder.GetHeightEx() / (10 * this.XPointCount); //分10份, 数据4 间距6 this.DistanceWidth = 4 * dInterval; this.DataWidth = 6 * dInterval; if (this.DistanceWidth > this.MaxDistanceWidth) { this.DistanceWidth = this.MaxDistanceWidth; dInterval = this.ChartBorder.GetHeightEx() / this.XPointCount; this.DataWidth = dInterval - this.MaxDistanceWidth; } } this.SplitXYCoordinate(); this.DrawHorizontal(); this.DrawVertical(); } this.GetXFromIndex = function (value) { if (value <= this.HorizontalMin) return this.ChartBorder.GetLeft(); if (value >= this.HorizontalMax) return this.ChartBorder.GetRight(); var width = this.ChartBorder.GetWidth() * (value - this.HorizontalMin) / (this.HorizontalMax - this.HorizontalMin); return this.ChartBorder.GetLeft() + width; } this.GetYFromData = function (index) { if (index < 0) index = 0; if (index > this.xPointCount - 1) index = this.xPointCount - 1; var offset = this.ChartBorder.GetBottom() - 2 - this.DistanceWidth / 2 - this.DataWidth / 2; for (var i = 1; i <= index; ++i) { offset -= this.DistanceWidth + this.DataWidth; } return offset; } //画Y轴 this.DrawHorizontal = function () { var top = this.ChartBorder.GetTopEx(); var bottom = this.ChartBorder.GetBottom(); var right = this.ChartBorder.GetRight(); var left = this.ChartBorder.GetLeft(); var yPrev = null; //上一个坐标y的值 for (var i in this.VerticalInfo) { let item = this.VerticalInfo[i]; var y = this.GetYFromData(item.Value); if (y != null && yPrev != null && Math.abs(y - yPrev) < 15) continue; //两个坐标在近了 就不画了 if (item.Message[0] != null) { if (this.VerticalInfo[i].Font != null) this.Canvas.font = item.Font; this.Canvas.fillStyle = item.TextColor; this.Canvas.textAlign = "right"; this.Canvas.textBaseline = "middle"; this.Canvas.fillText(item.Message[0], left - 2, y); } yPrev = y; } } //画X轴 this.DrawVertical = function () { var top = this.ChartBorder.GetTopEx(); var bottom = this.ChartBorder.GetBottom(); var right = this.ChartBorder.GetRight(); var left = this.ChartBorder.GetLeft(); var yText = bottom; if (this.XMessageAlign == 'bottom') yText = this.ChartBorder.GetChartHeight(); else this.XMessageAlign = 'top'; var xPrev = null; //上一个坐标x的值 let xPrevTextRight = null; for (var i in this.HorizontalInfo) { let item = this.HorizontalInfo[i]; var x = this.GetXFromIndex(item.Value); if (x > right) break; if (xPrev != null && Math.abs(x - xPrev) < this.MinXDistance) continue; if (this.IsShowXLine) { this.Canvas.strokeStyle = item.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(x), top); this.Canvas.lineTo(ToFixedPoint(x), bottom); this.Canvas.stroke(); } if (item.Message[0] != null) { let xTextRight = null; let xTextLeft = null; if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.fillStyle = item.TextColor; var testWidth = this.Canvas.measureText(item.Message[0]).width; if (x < testWidth / 2) { this.Canvas.textAlign = "left"; this.Canvas.textBaseline = this.XMessageAlign; xTextRight = x + testWidth; xTextLeft = x; } else { this.Canvas.textAlign = "center"; this.Canvas.textBaseline = this.XMessageAlign; xTextRight = x + testWidth / 2; xTextLeft = x - testWidth / 2; } if (xPrevTextRight != null && xPrevTextRight > xTextLeft) continue; //JSConsole.Chart.Log('[AverageWidthFrame::DrawVertical]', this.Canvas.fillStyle,x, yText); this.Canvas.fillText(item.Message[0], x, yText); xPrevTextRight = xTextRight; } xPrev = x; } } } function TooltipData() //提示信息 { this.ChartPaint; this.Data; } //缩放因子 var ZOOM_SEED = //0=柱子宽度 1=间距 [ [48, 10], [44, 10], [40, 9], [36, 9], [32, 8], [28, 8], [24, 7], [20, 7], [18, 6], [16, 6], [14, 5], [12, 5], [8, 4], [4, 4], [3, 3], [3, 1], [2,1], [1,1], [1,0] /* [49, 10], [46, 9], [43, 8], [41, 7.5], [39, 7], [37, 6], [31, 5.5], [27, 5], [23, 4.5], [21, 4], [18, 3.5], [16, 3], [13, 2.5], [11, 2], [8, 1.5], [6, 1], [3, 0.6], [2.2, 0.5], */ //太多了卡, //[1.1,0.3], //[0.9,0.2], [0.7,0.15], //[0.6,0.12], [0.5,0.1], [0.4,0.08], //[0.3,0.06], [0.2,0.04], [0.1,0.02] ]; //线段 多数据(一个X点有多条Y数据) 支持横屏 function ChartLineMultiData() { this.newMethod = IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Color = "rgb(255,193,37)"; //线段颜色 this.Draw = function () { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.Data || !this.Data.Data) return; var isHScreen = (this.ChartFrame.IsHScreen === true); var dataWidth = this.ChartFrame.DataWidth; var distanceWidth = this.ChartFrame.DistanceWidth; var chartright = this.ChartBorder.GetRight(); if (isHScreen) chartright = this.ChartBorder.GetBottom(); var xPointCount = this.ChartFrame.XPointCount; var bFirstPoint = true; var drawCount = 0; for (var i = this.Data.DataOffset, j = 0; i < this.Data.Data.length && j < xPointCount; ++i, ++j) { var aryValue = this.Data.Data[i]; if (aryValue == null) continue; var x = this.ChartFrame.GetXFromIndex(j); if (x > chartright) break; for (var index in aryValue) { var value = aryValue[index].Value; var y = this.ChartFrame.GetYFromData(value); if (bFirstPoint) { this.Canvas.strokeStyle = this.Color; this.Canvas.beginPath(); if (isHScreen) this.Canvas.moveTo(y, x); else this.Canvas.moveTo(x, y); bFirstPoint = false; } else { if (isHScreen) this.Canvas.lineTo(y, x); else this.Canvas.lineTo(x, y); } ++drawCount; } } if (drawCount > 0) this.Canvas.stroke(); } this.GetMaxMin = function () { var xPointCount = this.ChartFrame.XPointCount; var range = {}; range.Min = null; range.Max = null; if (!this.Data || !this.Data.Data) return range; for (var i = this.Data.DataOffset, j = 0; i < this.Data.Data.length && j < xPointCount; ++i, ++j) { var aryValue = this.Data.Data[i]; if (aryValue == null) continue; for (var index in aryValue) { var value = aryValue[index].Value; if (range.Max == null) range.Max = value; if (range.Min == null) range.Min = value; if (range.Max < value) range.Max = value; if (range.Min > value) range.Min = value; } } return range; } } //直线 水平直线 只有1个数据 支持横屏 function ChartStraightLine() { this.newMethod = IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Color = "rgb(255,193,37)"; //线段颜色 this.Draw = function () { if (!this.Data || !this.Data.Data) return; if (this.Data.Data.length != 1) return; var isHScreen = this.ChartFrame.IsHScreen; var dataWidth = this.ChartFrame.DataWidth; var distanceWidth = this.ChartFrame.DistanceWidth; var chartright = this.ChartBorder.GetRight(); if (isHScreen) chartright = this.ChartBorder.GetTop(); var xPointCount = this.ChartFrame.XPointCount; var yValue = this.Data.Data[0]; var y = this.ChartFrame.GetYFromData(yValue); var xLeft = this.ChartFrame.GetXFromIndex(0); var xRight = this.ChartFrame.GetXFromIndex(xPointCount - 1); var yFix = parseInt(y.toString()) + 0.5; this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(yFix, xLeft); this.Canvas.lineTo(yFix, xRight); } else { this.Canvas.moveTo(xLeft, yFix); this.Canvas.lineTo(xRight, yFix); } this.Canvas.strokeStyle = this.Color; this.Canvas.stroke(); } this.GetMaxMin = function () { var xPointCount = this.ChartFrame.XPointCount; var range = {}; range.Min = null; range.Max = null; if (!this.Data || !this.Data.Data) return range; if (this.Data.Data.length != 1) return range; range.Min = this.Data.Data[0]; range.Max = this.Data.Data[0]; return range; } } //分钟线叠加 支持横屏 function ChartOverlayMinutePriceLine() { this.newMethod = IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Color = "rgb(65,105,225)"; this.MainData; //主图数据 this.MainYClose; //主图股票的前收盘价 this.Name = "ChartOverlayMinutePriceLine"; this.Title; this.Symbol; //叠加的股票代码 this.YClose; //叠加的股票前收盘 this.Draw = function () { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } var isHScreen = (this.ChartFrame.IsHScreen === true); var dataWidth = this.ChartFrame.DataWidth; var distanceWidth = this.ChartFrame.DistanceWidth; var chartright = this.ChartBorder.GetRight(); if (isHScreen === true) chartright = this.ChartBorder.GetBottom(); var xPointCount = this.ChartFrame.XPointCount; var minuteCount = this.ChartFrame.MinuteCount; var bFirstPoint = true; var drawCount = 0; for (var i = this.Data.DataOffset, j = 0; i < this.Data.Data.length && j < xPointCount; ++i, ++j) { var value = this.Data.Data[i].Close; if (value == null) continue; var showValue = value / this.YClose * this.MainYClose; var x = this.ChartFrame.GetXFromIndex(j); var y = this.ChartFrame.GetYFromData(showValue); if (bFirstPoint) { this.Canvas.strokeStyle = this.Color; this.Canvas.beginPath(); if (isHScreen) this.Canvas.moveTo(y, x); else this.Canvas.moveTo(x, y); bFirstPoint = false; } else { if (isHScreen) this.Canvas.lineTo(y, x); else this.Canvas.lineTo(x, y); } ++drawCount; if (drawCount >= minuteCount) //上一天的数据和这天地数据线段要断开 { bFirstPoint = true; this.Canvas.stroke(); drawCount = 0; } } if (drawCount > 0) this.Canvas.stroke(); } this.GetMaxMin = function () { var xPointCount = this.ChartFrame.XPointCount; var range = {}; if (this.YClose == null) return range; range.Min = this.MainYClose; range.Max = this.MainYClose; for (var i = this.Data.DataOffset, j = 0; i < this.Data.Data.length && j < xPointCount; ++i, ++j) { var value = this.Data.Data[i].Close; if (value == null) continue; var value = value / this.YClose * this.MainYClose; if (range.Max == null) range.Max = value; if (range.Min == null) range.Min = value; if (range.Max < value) range.Max = value; if (range.Min > value) range.Min = value; } if (range.Max == this.MainYClose && range.Min == this.MainYClose) { range.Max = this.MainYClose + this.MainYClose * 0.1; range.Min = this.MainYClose - this.MainYClose * 0.1; return range; } var distance = Math.max(Math.abs(this.MainYClose - range.Max), Math.abs(this.MainYClose - range.Min)); range.Max = this.MainYClose + distance; range.Min = this.MainYClose - distance; return range; } } //基础图形的XY坐标互换柱子 function ChartXYSubBar() { this.newMethod = ChartBar; //派生 this.newMethod(); delete this.newMethod; this.BarID = 0; this.Draw = function () { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } var dataWidth = this.ChartFrame.DataWidth; var distanceWidth = this.ChartFrame.DistanceWidth; var chartTop = this.ChartBorder.GetTopEx(); var xPointCount = this.ChartFrame.XPointCount; var yOffset = this.ChartBorder.GetBottom() - distanceWidth / 2.0 - 2.0; var xMiddle = this.ChartFrame.GetXFromIndex(0); //0 刻度 if (dataWidth >= 4) { var barCount = this.ChartFrame.BarCount; var subBarWidth = dataWidth; var subBarOffset = 0; if (barCount > 0) //多柱子需要把框架柱子宽度的平均分割 { subBarWidth = dataWidth / barCount; subBarOffset = subBarWidth * this.BarID; //JSConsole.Chart.Log('[ChartXYSubBar::Draw] ', subBarWidth, this.BarID, subBarOffset); } xMiddle = ToFixedRect(xMiddle); //调整为整数 for (var i = this.Data.DataOffset, j = 0; i < this.Data.Data.length && j < xPointCount; ++i, ++j, yOffset -= (dataWidth + distanceWidth)) { var value = this.Data.Data[i]; if (value == null || value == 0) continue; var yBottom = yOffset + subBarOffset; var yTop = yOffset + subBarOffset - dataWidth; if (yBottom < chartTop) break; var x = this.ChartFrame.GetXFromIndex(value); if (value > 0) { this.Canvas.fillStyle = this.UpBarColor; let barWidth = ToFixedRect(Math.abs(x - xMiddle)); let barHeight = subBarWidth; if (Math.abs(chartTop - yBottom) < dataWidth) subBarWidth = Math.abs(chartTop - yBottom); //最后一根柱子可能会超出框架 this.Canvas.fillRect(xMiddle, ToFixedRect(yTop), barWidth, ToFixedRect(barHeight + 0.5)); } else { this.Canvas.fillStyle = this.DownBarColor; //高度调整为整数 let barWidth = ToFixedRect(Math.abs(x - xMiddle)); let barHeight = subBarWidth; if (Math.abs(chartTop - yBottom) < subBarWidth) barHeight = Math.abs(chartTop - yBottom); //最后一根柱子可能会超出框架 this.Canvas.fillRect(xMiddle, ToFixedRect(yTop), -barWidth, ToFixedRect(barHeight + 0.5)); } } } else //太细了 直接画柱子 { for (var i = this.Data.DataOffset, j = 0; i < this.Data.Data.length && j < xPointCount; ++i, ++j, yOffset -= (dataWidth + distanceWidth)) { var value = this.Data.Data[i]; if (value == null || value == 0) continue; var yBottom = yOffset; var yTop = yOffset - dataWidth; if (yTop < chartTop) break; var x = this.ChartFrame.GetXFromIndex(value); var y = this.ChartFrame.GetYFromData(j); if (value > 0) this.Canvas.strokeStyle = this.UpBarColor; else this.Canvas.strokeStyle = this.DownBarColor; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(x), y); this.Canvas.lineTo(ToFixedPoint(xMiddle), y); this.Canvas.stroke(); } } } } function ChartSubBar() { this.newMethod = ChartBar; //派生 this.newMethod(); delete this.newMethod; this.BarID = 0; this.Draw = function () { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } var dataWidth = this.ChartFrame.DataWidth; var distanceWidth = this.ChartFrame.DistanceWidth; var chartright = this.ChartBorder.GetRight(); var xPointCount = this.ChartFrame.XPointCount; var xOffset = this.ChartBorder.GetLeft() + distanceWidth / 2.0 + 2.0; var yBottom = this.ChartFrame.GetYFromData(0); if (dataWidth >= 4) { var barCount = this.ChartFrame.BarCount; var subBarWidth = dataWidth; var subBarOffset = 0; if (barCount > 0) //多柱子需要把框架柱子宽度的平均分割 { subBarWidth = dataWidth / barCount; subBarOffset = subBarWidth * this.BarID; //JSConsole.Chart.Log('[ChartSubBar::Draw] ', subBarWidth, this.BarID, subBarOffset); } yBottom = ToFixedRect(yBottom); //调整为整数 for (let i = this.Data.DataOffset, j = 0; i < this.Data.Data.length && j < xPointCount; ++i, ++j, xOffset += (dataWidth + distanceWidth)) { var value = this.Data.Data[i]; if (value == null || value == 0) continue; var left = xOffset + subBarOffset var right = xOffset + subBarOffset + subBarWidth; if (left > chartright) break; var x = this.ChartFrame.GetXFromIndex(j); var y = this.ChartFrame.GetYFromData(value); if (value > 0) { this.Canvas.fillStyle = this.UpBarColor; //高度调整为整数 let height = ToFixedRect(Math.abs(yBottom - y)); let barWidth = subBarWidth; if (chartright - left < subBarWidth) barWidth = chartright - left; if (yBottom - y > 0) y = yBottom - height; else y = yBottom + height; this.Canvas.fillRect(ToFixedRect(left), y, ToFixedRect(barWidth), height); } else { this.Canvas.fillStyle = this.DownBarColor; //高度调整为整数 let height = ToFixedRect(Math.abs(yBottom - y)); let barWidth = subBarWidth; if (chartright - left < subBarWidth) barWidth = chartright - left; if (yBottom - y > 0) y = yBottom - height; else y = yBottom + height; this.Canvas.fillRect(ToFixedRect(left), y, ToFixedRect(subBarWidth), -height); } } } else //太细了 直接画柱子 { for (let i = this.Data.DataOffset, j = 0; i < this.Data.Data.length && j < xPointCount; ++i, ++j, xOffset += (dataWidth + distanceWidth)) { var value = this.Data.Data[i]; if (value == null || value == 0) continue; var left = xOffset; var right = xOffset + dataWidth; if (right > chartright) break; var x = this.ChartFrame.GetXFromIndex(j); var y = this.ChartFrame.GetYFromData(value); if (value > 0) this.Canvas.strokeStyle = this.UpBarColor; else this.Canvas.strokeStyle = this.DownBarColor; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(x), y); this.Canvas.lineTo(ToFixedPoint(x), yBottom); this.Canvas.stroke(); } } } } //柱子 支持横屏 function ChartBar() { this.newMethod = IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.UpBarColor = g_JSChartResource.UpBarColor; this.DownBarColor = g_JSChartResource.DownBarColor; this.Draw = function () { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } var isHScreen = (this.ChartFrame.IsHScreen === true); var dataWidth = this.ChartFrame.DataWidth; var distanceWidth = this.ChartFrame.DistanceWidth; var chartright = this.ChartBorder.GetRight(); if (isHScreen) chartright = this.ChartBorder.GetBottom(); var xPointCount = this.ChartFrame.XPointCount; var xOffset = this.ChartBorder.GetLeft() + distanceWidth / 2.0 + 2.0; if (isHScreen) xOffset = this.ChartBorder.GetTop() + distanceWidth / 2.0 + 2.0; var bFirstPoint = true; var drawCount = 0; var yBottom = this.ChartFrame.GetYFromData(0); if (dataWidth >= 4) { yBottom = ToFixedRect(yBottom); //调整为整数 for (var i = this.Data.DataOffset, j = 0; i < this.Data.Data.length && j < xPointCount; ++i, ++j, xOffset += (dataWidth + distanceWidth)) { var value = this.Data.Data[i]; if (value == null || value == 0) continue; var left = xOffset; var right = xOffset + dataWidth; if (right > chartright) break; var x = this.ChartFrame.GetXFromIndex(j); var y = this.ChartFrame.GetYFromData(value); if (value > 0) { this.Canvas.fillStyle = this.UpBarColor; if (isHScreen) { let height = ToFixedRect(Math.abs(yBottom - y)); //高度调整为整数 y = Math.min(yBottom, y); this.Canvas.fillRect(y, ToFixedRect(left), height, ToFixedRect(dataWidth)); } else { let height = ToFixedRect(Math.abs(yBottom - y)); //高度调整为整数 if (yBottom - y > 0) y = yBottom - height; else y = yBottom + height; this.Canvas.fillRect(ToFixedRect(left), y, ToFixedRect(dataWidth), height); } } else { this.Canvas.fillStyle = this.DownBarColor; //高度调整为整数 let height = ToFixedRect(Math.abs(yBottom - y)); if (yBottom - y > 0) y = yBottom - height; else y = yBottom + height; this.Canvas.fillRect(ToFixedRect(left), y, ToFixedRect(dataWidth), -height); } } } else //太细了 直接画柱子 { for (var i = this.Data.DataOffset, j = 0; i < this.Data.Data.length && j < xPointCount; ++i, ++j, xOffset += (dataWidth + distanceWidth)) { var value = this.Data.Data[i]; if (value == null || value == 0) continue; var left = xOffset; var right = xOffset + dataWidth; if (right > chartright) break; var x = this.ChartFrame.GetXFromIndex(j); var y = this.ChartFrame.GetYFromData(value); if (value > 0) this.Canvas.strokeStyle = this.UpBarColor; else this.Canvas.strokeStyle = this.DownBarColor; this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(y, ToFixedPoint(x)); this.Canvas.lineTo(yBottom, ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x), y); this.Canvas.lineTo(ToFixedPoint(x), yBottom); } this.Canvas.stroke(); } } } this.GetMaxMin = function () { var xPointCount = this.ChartFrame.XPointCount; var range = {}; range.Min = 0; range.Max = null; for (var i = this.Data.DataOffset, j = 0; i < this.Data.Data.length && j < xPointCount; ++i, ++j) { var value = this.Data.Data[i]; if (range.Max == null) range.Max = value; if (range.Max < value) range.Max = value; if (range.Min > value) range.Min = value; } return range; } } /* 画图工具 */ function IChartDrawPicture() { this.Frame; this.Canvas; this.Point = new Array() //画图的点 this.Value = new Array(); //XValue,YValue this.PointCount = 2; //画点的个数 this.Status = 0; //0 开始画 1 完成第1个点 2 完成第2个点 10 完成 20 移动 this.MovePointIndex = null; //移动哪个点 0-10 对应Point索引 100 整体移动 this.LineColor = g_JSChartResource.DrawPicture.LineColor[0]; //线段颜色 this.PointColor = g_JSChartResource.DrawPicture.PointColor[0]; this.Draw = function () { } //Point => Value this.PointToValue = function () { if (!this.Frame) return false; var data = this.Frame.Data; if (!data) return false; for (var i in this.Point) { var item = this.Point[i]; var xValue = parseInt(this.Frame.GetXData(item.X)) + data.DataOffset; var yValue = this.Frame.GetYData(item.Y); this.Value[i] = {}; this.Value[i].XValue = xValue; this.Value[i].YValue = yValue; } return true; } this.IsPointIn = function (x, y) { return false; } //Value => Point this.ValueToPoint = function () { if (!this.Frame) return false; var data = this.Frame.Data; if (!data) return false; this.Point = []; for (var i in this.Value) { var item = this.Value[i]; var pt = new Point(); pt.X = this.Frame.GetXFromIndex(item.XValue - data.DataOffset); pt.Y = this.Frame.GetYFromData(item.YValue); this.Point[i] = pt; } } //xStep,yStep 移动的偏移量 this.Move = function (xStep, yStep) { if (this.Status != 20) return fasle; if (!this.Frame) return false; var data = this.Frame.Data; if (!data) return false; if (this.MovePointIndex == 100) //整体移动 { for (var i in this.Point) { this.Point[i].X += xStep; this.Point[i].Y += yStep; } } else if (this.MovePointIndex == 0 || this.MovePointIndex == 1) { this.Point[this.MovePointIndex].X += xStep; this.Point[this.MovePointIndex].Y += yStep; } } this.ClipFrame = function () { var left = this.Frame.ChartBorder.GetLeft(); var top = this.Frame.ChartBorder.GetTopEx(); var width = this.Frame.ChartBorder.GetWidth(); var height = this.Frame.ChartBorder.GetHeightEx(); this.Canvas.save(); this.Canvas.beginPath(); this.Canvas.rect(left, top, width, height); this.Canvas.clip(); } //计算需要画的点的坐标 this.CalculateDrawPoint = function () { if (this.Status < 2) return null; if (!this.Point.length || !this.Frame) return null; var drawPoint = new Array(); if (this.Status == 10) { var data = this.Frame.Data; if (!data) return null; for (var i in this.Value) { var item = this.Value[i]; var pt = new Point(); pt.X = this.Frame.GetXFromIndex(item.XValue - data.DataOffset); pt.Y = this.Frame.GetYFromData(item.YValue); drawPoint.push(pt); } } else { drawPoint = this.Point; } return drawPoint; } this.DrawPoint = function (aryPoint) { if (!aryPoint || aryPoint.length <= 0) return; //画点 this.ClipFrame(); for (var i in aryPoint) { var item = aryPoint[i]; this.Canvas.beginPath(); this.Canvas.arc(item.X, item.Y, 5, 0, 360, false); this.Canvas.fillStyle = this.PointColor; //填充颜色 this.Canvas.fill(); //画实心圆 this.Canvas.closePath(); } this.Canvas.restore(); } } /* 画图工具-线段 */ function ChartDrawPictureLine() { this.newMethod = IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.Draw = function () { var drawPoint = this.CalculateDrawPoint(); if (!drawPoint) return; this.ClipFrame(); for (var i in drawPoint) { var item = drawPoint[i]; if (i == 0) { this.Canvas.beginPath(); this.Canvas.moveTo(item.X, item.Y); } else { this.Canvas.lineTo(item.X, item.Y); } } this.Canvas.strokeStyle = this.LineColor; this.Canvas.stroke(); this.Canvas.closePath(); this.Canvas.restore(); //画点 this.DrawPoint(drawPoint); } //0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上 this.IsPointIn = function (x, y) { if (!this.Frame || this.Status != 10) return -1; var data = this.Frame.Data; if (!data) return -1; //是否在点上 var aryPoint = new Array(); for (var i in this.Value) { var item = this.Value[i]; var pt = new Point(); pt.X = this.Frame.GetXFromIndex(item.XValue - data.DataOffset); pt.Y = this.Frame.GetYFromData(item.YValue); this.Canvas.beginPath(); this.Canvas.arc(pt.X, pt.Y, 5, 0, 360); //JSConsole.Chart.Log('['+i+']'+'x='+x+' y='+y+' dataX='+pt.X+" dataY="+pt.Y); if (this.Canvas.isPointInPath(x, y)) return i; aryPoint.push(pt); } //是否在线段上 this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y + 5); this.Canvas.lineTo(aryPoint[0].X, aryPoint[0].Y - 5); this.Canvas.lineTo(aryPoint[1].X, aryPoint[1].Y - 5); this.Canvas.lineTo(aryPoint[1].X, aryPoint[1].Y + 5); this.Canvas.closePath(); if (this.Canvas.isPointInPath(x, y)) return 100; return -1; } } /* 画图工具-射线 */ function ChartDrawPictureHaflLine() { this.newMethod = IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.Draw = function () { var drawPoint = this.CalculateDrawPoint(); if (!drawPoint || drawPoint.length != 2) return; this.ClipFrame(); this.Canvas.beginPath(); this.Canvas.moveTo(drawPoint[0].X, drawPoint[0].Y); this.Canvas.lineTo(drawPoint[1].X, drawPoint[1].Y); var endPoint = this.CalculateEndPoint(drawPoint); this.Canvas.lineTo(endPoint.X, endPoint.Y); this.Canvas.strokeStyle = this.LineColor; this.Canvas.stroke(); this.Canvas.closePath(); this.Canvas.restore(); //画点 this.DrawPoint(drawPoint); } this.CalculateEndPoint = function (aryPoint) { var left = this.Frame.ChartBorder.GetLeft(); var right = this.Frame.ChartBorder.GetRight(); var a = aryPoint[1].X - aryPoint[0].X; var b = aryPoint[1].Y - aryPoint[0].Y; if (a > 0) { var a1 = right - aryPoint[0].X; var b1 = a1 * b / a; var y = b1 + aryPoint[0].Y; var pt = new Point(); pt.X = right; pt.Y = y; return pt; } else { var a1 = aryPoint[0].X - left; var b1 = a1 * b / Math.abs(a); var y = b1 + aryPoint[0].Y; var pt = new Point(); pt.X = left; pt.Y = y; return pt; } } //0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上 this.IsPointIn = function (x, y) { if (!this.Frame || this.Status != 10) return -1; var data = this.Frame.Data; if (!data) return -1; //是否在点上 var aryPoint = new Array(); for (var i in this.Value) { var item = this.Value[i]; var pt = new Point(); pt.X = this.Frame.GetXFromIndex(item.XValue - data.DataOffset); pt.Y = this.Frame.GetYFromData(item.YValue); this.Canvas.beginPath(); this.Canvas.arc(pt.X, pt.Y, 5, 0, 360); //JSConsole.Chart.Log('['+i+']'+'x='+x+' y='+y+' dataX='+pt.X+" dataY="+pt.Y); if (this.Canvas.isPointInPath(x, y)) return i; aryPoint.push(pt); } //是否在线段上 this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y + 5); this.Canvas.lineTo(aryPoint[0].X, aryPoint[0].Y - 5); this.Canvas.lineTo(aryPoint[1].X, aryPoint[1].Y - 5); this.Canvas.lineTo(aryPoint[1].X, aryPoint[1].Y + 5); this.Canvas.closePath(); if (this.Canvas.isPointInPath(x, y)) return 100; return -1; } } /* 画图工具-矩形 */ function ChartDrawPictureRect() { this.newMethod = IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.Draw = function () { var drawPoint = this.CalculateDrawPoint(); if (!drawPoint || drawPoint.length != 2) return; this.ClipFrame(); this.Canvas.beginPath(); this.Canvas.rect(drawPoint[0].X, drawPoint[0].Y, drawPoint[1].X - drawPoint[0].X, drawPoint[1].Y - drawPoint[0].Y); this.Canvas.strokeStyle = this.LineColor; this.Canvas.stroke(); this.Canvas.closePath(); this.Canvas.restore(); //画点 this.DrawPoint(drawPoint); } //0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上 this.IsPointIn = function (x, y) { if (!this.Frame || this.Status != 10) return -1; var data = this.Frame.Data; if (!data) return -1; //是否在点上 var aryPoint = new Array(); for (var i in this.Value) { var item = this.Value[i]; var pt = new Point(); pt.X = this.Frame.GetXFromIndex(item.XValue - data.DataOffset); pt.Y = this.Frame.GetYFromData(item.YValue); this.Canvas.beginPath(); this.Canvas.arc(pt.X, pt.Y, 5, 0, 360); //JSConsole.Chart.Log('['+i+']'+'x='+x+' y='+y+' dataX='+pt.X+" dataY="+pt.Y); if (this.Canvas.isPointInPath(x, y)) return i; aryPoint.push(pt); } //是否在矩形边框上 var linePoint = [{ X: aryPoint[0].X, Y: aryPoint[0].Y }, { X: aryPoint[1].X, Y: aryPoint[0].Y }]; if (this.IsPointInLine(linePoint, x, y)) return 100; linePoint = [{ X: aryPoint[1].X, Y: aryPoint[0].Y }, { X: aryPoint[1].X, Y: aryPoint[1].Y }]; if (this.IsPointInLine2(linePoint, x, y)) return 100; linePoint = [{ X: aryPoint[1].X, Y: aryPoint[1].Y }, { X: aryPoint[0].X, Y: aryPoint[1].Y }]; if (this.IsPointInLine(linePoint, x, y)) return 100; linePoint = [{ X: aryPoint[0].X, Y: aryPoint[1].Y }, { X: aryPoint[0].X, Y: aryPoint[0].Y }]; if (this.IsPointInLine2(linePoint, x, y)) return 100; return -1; } //点是否在线段上 水平线段 this.IsPointInLine = function (aryPoint, x, y) { this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y + 5); this.Canvas.lineTo(aryPoint[0].X, aryPoint[0].Y - 5); this.Canvas.lineTo(aryPoint[1].X, aryPoint[1].Y - 5); this.Canvas.lineTo(aryPoint[1].X, aryPoint[1].Y + 5); this.Canvas.closePath(); if (this.Canvas.isPointInPath(x, y)) return true; } //垂直线段 this.IsPointInLine2 = function (aryPoint, x, y) { this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X - 5, aryPoint[0].Y); this.Canvas.lineTo(aryPoint[0].X + 5, aryPoint[0].Y); this.Canvas.lineTo(aryPoint[1].X + 5, aryPoint[1].Y); this.Canvas.lineTo(aryPoint[1].X - 5, aryPoint[1].Y); this.Canvas.closePath(); if (this.Canvas.isPointInPath(x, y)) return true; } } /* 画图工具-弧形 */ function ChartDrawPictureArc() { this.newMethod = IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.Draw = function () { var drawPoint = this.CalculateDrawPoint(); if (!drawPoint || drawPoint.length != 2) return; this.ClipFrame(); //this.Canvas.beginPath(); //this.Canvas.rect(drawPoint[0].X,drawPoint[0].Y,drawPoint[1].X-drawPoint[0].X,drawPoint[1].Y-drawPoint[0].Y); if (drawPoint[0].X < drawPoint[1].X && drawPoint[0].Y > drawPoint[1].Y) // 第一象限 { var a = drawPoint[1].X - drawPoint[0].X; var b = drawPoint[0].Y - drawPoint[1].Y; var step = (a > b) ? 1 / a : 1 / b; var xcenter = drawPoint[0].X; var ycenter = drawPoint[1].Y; this.Canvas.beginPath(); this.Canvas.moveTo(drawPoint[0].X, drawPoint[0].Y); for (var i = 1.5 * Math.PI; i < 2 * Math.PI; i += step) { this.Canvas.lineTo(xcenter + a * Math.cos(i), ycenter + b * Math.sin(i) * -1); } for (var j = 0; j <= 0.5 * Math.PI; j += step) { this.Canvas.lineTo(xcenter + a * Math.cos(j), ycenter + b * Math.sin(j) * -1); } } else if (drawPoint[0].X > drawPoint[1].X && drawPoint[0].Y > drawPoint[1].Y) // 第二象限 { var a = drawPoint[0].X - drawPoint[1].X; var b = drawPoint[0].Y - drawPoint[1].Y; var step = (a > b) ? 1 / a : 1 / b; var xcenter = drawPoint[1].X; var ycenter = drawPoint[0].Y; this.Canvas.beginPath(); this.Canvas.moveTo(drawPoint[0].X, drawPoint[0].Y); for (var i = 0; i <= Math.PI; i += step) { this.Canvas.lineTo(xcenter + a * Math.cos(i), ycenter + b * Math.sin(i) * -1); } } else if (drawPoint[0].X > drawPoint[1].X && drawPoint[0].Y < drawPoint[1].Y) // 第三象限 { var a = drawPoint[0].X - drawPoint[1].X; var b = drawPoint[1].Y - drawPoint[0].Y; var step = (a > b) ? 1 / a : 1 / b; var xcenter = drawPoint[0].X; var ycenter = drawPoint[1].Y; this.Canvas.beginPath(); this.Canvas.moveTo(drawPoint[0].X, drawPoint[0].Y); for (var i = 0.5 * Math.PI; i <= 1.5 * Math.PI; i += step) { this.Canvas.lineTo(xcenter + a * Math.cos(i), ycenter + b * Math.sin(i) * -1); } } else if (drawPoint[0].X < drawPoint[1].X && drawPoint[0].Y < drawPoint[1].Y) // 第四象限 { var a = drawPoint[1].X - drawPoint[0].X; var b = drawPoint[1].Y - drawPoint[0].Y; var step = (a > b) ? 1 / a : 1 / b; var xcenter = drawPoint[1].X; var ycenter = drawPoint[0].Y; this.Canvas.beginPath(); this.Canvas.moveTo(drawPoint[0].X, drawPoint[0].Y); for (var i = Math.PI; i <= 2 * Math.PI; i += step) { this.Canvas.lineTo(xcenter + a * Math.cos(i), ycenter + b * Math.sin(i) * -1); } } this.Canvas.strokeStyle = this.LineColor; this.Canvas.stroke(); //this.Canvas.closePath(); this.Canvas.restore(); //画点 this.DrawPoint(drawPoint); } //0-10 鼠标对应的点索引 100=鼠标在正个图形上 -1 鼠标不在图形上 this.IsPointIn = function (x, y) { if (!this.Frame || this.Status != 10) return -1; var data = this.Frame.Data; if (!data) return -1; //是否在点上 var aryPoint = new Array(); for (var i in this.Value) { var item = this.Value[i]; var pt = new Point(); pt.X = this.Frame.GetXFromIndex(item.XValue - data.DataOffset); pt.Y = this.Frame.GetYFromData(item.YValue); this.Canvas.beginPath(); this.Canvas.arc(pt.X, pt.Y, 5, 0, 360); //JSConsole.Chart.Log('['+i+']'+'x='+x+' y='+y+' dataX='+pt.X+" dataY="+pt.Y); if (this.Canvas.isPointInPath(x, y)) return i; aryPoint.push(pt); } //是否在弧线上 var ArcPoint = [{ X: aryPoint[0].X, Y: aryPoint[0].Y }, { X: aryPoint[1].X, Y: aryPoint[1].Y }]; if (this.IsPointInArc(ArcPoint, x, y)) return 100; return -1; } this.IsPointInArc = function (aryPoint, x, y) { if (aryPoint.length != 2) return false; if (aryPoint[0].X < aryPoint[1].X && aryPoint[0].Y > aryPoint[1].Y) // 第一象限 { var a = aryPoint[1].X - aryPoint[0].X; var b = aryPoint[0].Y - aryPoint[1].Y; var step = (a > b) ? 1 / a : 1 / b; var ainer = a * 0.8; var biner = b * 0.8; var stepiner = (ainer > biner) ? 1 / ainer : 1 / biner; var xcenter = aryPoint[0].X; var ycenter = aryPoint[1].Y; this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y); for (var i = 1.5 * Math.PI; i < 2 * Math.PI; i += step) { this.Canvas.lineTo(xcenter + a * Math.cos(i), ycenter + b * Math.sin(i) * -1); } for (var j = 0; j <= 0.5 * Math.PI; j += step) { this.Canvas.lineTo(xcenter + a * Math.cos(j), ycenter + b * Math.sin(j) * -1); } for (var k = 0.5 * Math.PI; k >= 0; k -= stepiner) { this.Canvas.lineTo(xcenter + ainer * Math.cos(k), ycenter + biner * Math.sin(j) * -1); } for (var l = 2 * Math.PI; l >= 1.5 * Math.PI; l -= stepiner) { this.Canvas.lineTo(xcenter + ainer * Math.cos(l), ycenter + biner * Math.sin(l) * -1); } this.Canvas.closePath(); } else if (aryPoint[0].X > aryPoint[1].X && aryPoint[0].Y > aryPoint[1].Y) // 第二象限 { var a = aryPoint[0].X - aryPoint[1].X; var b = aryPoint[0].Y - aryPoint[1].Y; var step = (a > b) ? 1 / a : 1 / b; var ainer = a * 0.8; var biner = b * 0.8; var stepiner = (ainer > biner) ? 1 / ainer : 1 / biner; var xcenter = aryPoint[1].X; var ycenter = aryPoint[0].Y; this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y); for (var i = 0; i <= Math.PI; i += step) { this.Canvas.lineTo(xcenter + a * Math.cos(i), ycenter + b * Math.sin(i) * -1); } for (var j = Math.PI; j >= 0; j -= stepiner) { this.Canvas.lineTo(xcenter + ainer * Math.cos(j), ycenter + biner * Math.sin(j) * -1); } this.Canvas.closePath(); } else if (aryPoint[0].X > aryPoint[1].X && aryPoint[0].Y < aryPoint[1].Y) // 第三象限 { var a = aryPoint[0].X - aryPoint[1].X; var b = aryPoint[1].Y - aryPoint[0].Y; var step = (a > b) ? 1 / a : 1 / b; var ainer = a * 0.8; var biner = b * 0.8; var stepiner = (ainer > biner) ? 1 / ainer : 1 / biner; var xcenter = aryPoint[0].X; var ycenter = aryPoint[1].Y; this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y); for (var i = 0.5 * Math.PI; i <= 1.5 * Math.PI; i += step) { this.Canvas.lineTo(xcenter + a * Math.cos(i), ycenter + b * Math.sin(i) * -1); } for (var j = 1.5 * Math.PI; j >= 0.5 * Math.PI; j -= stepiner) { this.Canvas.lineTo(xcenter + ainer * Math.cos(j), ycenter + biner * Math.sin(j) * -1); } this.Canvas.closePath(); } else if (aryPoint[0].X < aryPoint[1].X && aryPoint[0].Y < aryPoint[1].Y) // 第四象限 { var a = aryPoint[1].X - aryPoint[0].X; var b = aryPoint[1].Y - aryPoint[0].Y; var step = (a > b) ? 1 / a : 1 / b; var ainer = a * 0.8; var biner = b * 0.8; var stepiner = (ainer > biner) ? 1 / ainer : 1 / biner; var xcenter = aryPoint[1].X; var ycenter = aryPoint[0].Y; this.Canvas.beginPath(); this.Canvas.moveTo(aryPoint[0].X, aryPoint[0].Y); for (var i = Math.PI; i <= 2 * Math.PI; i += step) { this.Canvas.lineTo(xcenter + a * Math.cos(i), ycenter + b * Math.sin(i) * -1); } for (var j = 2 * Math.PI; j >= Math.PI; j -= stepiner) { this.Canvas.lineTo(xcenter + ainer * Math.cos(j), ycenter + biner * Math.sin(j) * -1); } this.Canvas.closePath(); } if (this.Canvas.isPointInPath(x, y)) return true; else return false; } } /* 指标列表 指标信息都在这里,不够后面再加字段 */ function JSIndexMap() { } JSIndexMap.Get = function (id) { var indexMap = new Map( [ //公司自己的指标 ["市场多空", { IsMainIndex: false, Create: function () { return new MarketLongShortIndex() } }], ["市场择时", { IsMainIndex: false, Create: function () { return new MarketTimingIndex() } }], ["市场关注度", { IsMainIndex: false, Create: function () { return new MarketAttentionIndex() } }], ["指数热度", { IsMainIndex: false, Create: function () { return new MarketHeatIndex() } }], ["自定义指数热度", { IsMainIndex: false, Create: function () { return new CustonIndexHeatIndex() }, Name: '自定义指数热度' }], ["财务粉饰", { IsMainIndex: false, Create: function () { return new BenfordIndex() } }], //能图指标 //["能图-趋势", { IsMainIndex: false, Create: function () { return new LighterIndex1() }, Name: '大盘/个股趋势' }], //["能图-位置研判", { IsMainIndex: false, Create: function () { return new LighterIndex2() }, Name: '位置研判' }], //["能图-点位研判", { IsMainIndex: false, Create: function () { return new LighterIndex3() }, Name: '点位研判' }], //["能图-资金分析", { IsMainIndex: false, Create: function () { return new LighterIndex4() }, Name: '资金分析' }], //["能图-市场关注度", { IsMainIndex: false, Create: function () { return new LighterIndex5() }, Name: '市场关注度' }] ] ); return indexMap.get(id); } ///////////////////////////////////////////////////////////////////////////////////////////// // K线图 控件 // this.ChartPaint[0] K线画法 这个不要修改 // // function KLineChartContainer(uielement) { var _self = this; this.newMethod = JSChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.ClassName = 'KLineChartContainer'; this.WindowIndex = new Array(); this.ColorIndex; //五彩K线 this.TradeIndex; //交易指标/专家系统 this.Symbol; this.Name; this.Period = 0; //周期 0=日线 1=周线 2=月线 3=年线 4=1分钟 5=5分钟 6=15分钟 7=30分钟 8=60分钟 9=季线 10=分笔线 11=120分钟 12=240分钟 this.IsApiPeriod = false; //使用API计算周期 this.Right = 0; //复权 0 不复权 1 前复权 2 后复权 this.SourceData; //原始的历史数据 this.MaxReqeustDataCount = 3000; //数据个数 this.MaxRequestMinuteDayCount = 5; //分钟数据请求的天数 this.PageSize = 200; //每页数据个数 this.KLineDrawType = 0; //0=K线 1=收盘价线 2=美国线 this.LoadDataSplashTitle = '下载历史数据'; this.IsAutoUpdate = false; //是否自动更新行情数据 this.AutoUpdateFrequency = 30000; //30秒更新一次数据 this.AutoUpdateTimer; //自动定时器 this.RightSpaceCount=1; this.SourceDataLimit = new Map(); //每个周期缓存数据最大个数 key=周期 value=最大个数 this.KLineSize=null; //{ DataWidth:, } this.StepPixel = 4; //移动一个数据需要的像素 this.ZoomStepPixel = 5; //放大缩小手势需要的最小像素 this.EnableZoomUpDown=null; //是否手势/键盘/鼠标允许缩放{ Touch:true/false, Mouse:true/false, Keyboard:true/false, Wheel:true/false } this.DragDownload = { Day: { Enable: false, IsEnd: false, Status: 0 }, //日线数据拖拽下载(暂不支持) Status: 0空闲 1 下载中 Minute: { Enable: false, IsEnd: false, status: 0 } //分钟数据拖拽下载 }; this.KLineApiUrl = g_JSChartResource.Domain + "/API/KLine2"; //历史K线api地址 this.MinuteKLineApiUrl = g_JSChartResource.Domain + '/API/KLine3'; //历史分钟数据 this.RealtimeApiUrl = g_JSChartResource.Domain + "/API/Stock"; //实时行情api地址 this.KLineMatchUrl = g_JSChartResource.Domain + "/API/KLineMatch"; //形态匹配 this.DragMinuteKLineApiUrl = g_JSChartResource.Domain + '/API/KLine4'; //拖动数据下载 this.DragKLineApiUrl = g_JSChartResource.Domain + '/API/KLine5'; //拖动日K数据下载 this.BeforeBindMainData = null; //function(funcName) 在BindMainData() 调用前回调用 this.AfterBindMainData = null; //function(funcName) 在BindMainData() 调用前后调用 this.ResetDragDownload = function () { this.DragDownload.Day.Status = 0; this.DragDownload.Day.IsEnd=false; this.DragDownload.Minute.Status = 0; this.DragDownload.Minute.isEnd=false; } this.ChartOperator = function (obj) //图形控制函数 {ID:JSCHART_OPERATOR_ID, ...参数 } { var id = obj.ID; if (id === JSCHART_OPERATOR_ID.OP_SCROLL_LEFT || id === JSCHART_OPERATOR_ID.OP_SCROLL_RIGHT) //左右移动 { Step:移动数据个数 } { var isLeft = (id === JSCHART_OPERATOR_ID.OP_SCROLL_LEFT ? true : false); var step = 1; if (obj.Step > 0) step = obj.Step; if (this.DataMove(step * this.StepPixel, isLeft)) //每次移动一个数据 { this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.ResetFrameXYSplit(); this.Draw(); } else { if (id===JSCHART_OPERATOR_ID.OP_SCROLL_RIGHT && this.DragDownloadData) this.DragDownloadData(); } } else if (id === JSCHART_OPERATOR_ID.OP_ZOOM_IN || id === JSCHART_OPERATOR_ID.OP_ZOOM_OUT) //缩放 { var cursorIndex = {}; cursorIndex.Index = parseInt(Math.abs(this.CursorIndex - 0.5).toFixed(0)); if (id === JSCHART_OPERATOR_ID.OP_ZOOM_IN) { if (!this.Frame.ZoomUp(cursorIndex)) return; } else { if (!this.Frame.ZoomDown(cursorIndex)) return; } this.CursorIndex = cursorIndex.Index; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); } else if (id === JSCHART_OPERATOR_ID.OP_GOTO_HOME) //返回最新 { var hisData = null; if (!this.Frame.Data) hisData = this.Frame.Data; else hisData = this.Frame.SubFrame[0].Frame.Data; if (!hisData) return; //数据还没有到达 var showCount = this.PageSize; //var pageSize = this.GetMaxMinPageSize(); //if (pageSize.Max < showCount) showCount = pageSize.Max; //else if (pageSize.Min > showCount) showCount = pageSize.Min; for (var i in this.Frame.SubFrame) //设置一屏显示的数据个数 { var item = this.Frame.SubFrame[i].Frame; item.XPointCount = showCount; } var index = hisData.Data.length - showCount; hisData.DataOffset = index; this.CursorIndex = 0; this.LastPoint.X = null; this.LastPoint.Y = null; JSConsole.Chart.Log(`[KLineChartContainer::ChartOperator] OP_GOTO_HOME, dataOffset=${hisData.DataOffset} CursorIndex=${this.CursorIndex} PageSize=${showCount}`); this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); this.UpdatePointByCursorIndex(); //更新十字光标位子 } } //创建windowCount 窗口个数 this.Create = function (windowCount) { this.UIElement.JSChartContainer = this; //创建十字光标 this.ChartCorssCursor = new ChartCorssCursor(); this.ChartCorssCursor.Canvas = this.Canvas; this.ChartCorssCursor.StringFormatX = g_DivTooltipDataForamt.Create("CorssCursor_XStringFormat"); this.ChartCorssCursor.StringFormatX.LanguageID=this.LanguageID; this.ChartCorssCursor.StringFormatY = g_DivTooltipDataForamt.Create("CorssCursor_YStringFormat"); this.ChartCorssCursor.StringFormatY.LanguageID = this.LanguageID; //创建等待提示 this.ChartSplashPaint = new ChartSplashPaint(); this.ChartSplashPaint.Canvas = this.Canvas; this.ChartSplashPaint.SplashTitle = this.LoadDataSplashTitle; this.ChartSplashPaint.HQChart=this; //创建框架容器 this.Frame = new HQTradeFrame(); this.Frame.ChartBorder = new ChartBorder(); this.Frame.ChartBorder.UIElement = this.UIElement; this.Frame.ChartBorder.Top = 30; this.Frame.ChartBorder.Left = 5; this.Frame.ChartBorder.Bottom = 20; this.Frame.Canvas = this.Canvas; this.ChartCorssCursor.Frame = this.Frame; //十字光标绑定框架 this.ChartSplashPaint.Frame = this.Frame; this.CreateChildWindow(windowCount); this.CreateMainKLine(); //子窗口动态标题 for (var i in this.Frame.SubFrame) { var titlePaint = new DynamicChartTitlePainting(); titlePaint.Frame = this.Frame.SubFrame[i].Frame; titlePaint.Canvas = this.Canvas; titlePaint.LanguageID = this.LanguageID; this.Frame.SubFrame[i].Frame.TitlePaint = titlePaint; this.TitlePaint.push(titlePaint); } } //创建子窗口 this.CreateChildWindow = function (windowCount) { for (var i = 0; i < windowCount; ++i) { var border = new ChartBorder(); border.UIElement = this.UIElement; var frame = new KLineFrame(); frame.Canvas = this.Canvas; frame.ChartBorder = border; frame.Identify = i; //窗口序号 frame.RightSpaceCount = this.RightSpaceCount; //右边 frame.HorizontalMax = 20; frame.HorizontalMin = 10; if (i == 0) { frame.YSplitOperator = new FrameSplitKLinePriceY(); frame.YSplitOperator.FrameSplitData = this.FrameSplitData.get('price'); frame.YSplitOperator.FrameSplitData2 = this.FrameSplitData.get('double'); frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); } border.BottomSpace = 12; //主图上下留空间 border.TopSpace = 12; } else { frame.YSplitOperator = new FrameSplitY(); frame.YSplitOperator.FrameSplitData = this.FrameSplitData.get('double'); frame.YSplitOperator.LanguageID = this.LanguageID; frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); } } frame.YSplitOperator.Frame = frame; frame.YSplitOperator.ChartBorder = border; frame.XSplitOperator = new FrameSplitKLineX(); frame.XSplitOperator.Frame = frame; frame.XSplitOperator.ChartBorder = border; if (i != windowCount - 1) frame.XSplitOperator.ShowText = false; for (var j = frame.HorizontalMin; j <= frame.HorizontalMax; j += 1) { frame.HorizontalInfo[j] = new CoordinateInfo(); frame.HorizontalInfo[j].Value = j; if (i == 0 && j == frame.HorizontalMin) continue; frame.HorizontalInfo[j].Message[1] = j.toString(); frame.HorizontalInfo[j].Font = "14px 微软雅黑"; } var subFrame = new SubFrameItem(); subFrame.Frame = frame; if (i == 0) subFrame.Height = 20; else subFrame.Height = 10; this.Frame.SubFrame[i] = subFrame; } } this.CreateSubFrameItem = function (id) { var border = new ChartBorder(); border.UIElement = this.UIElement; var frame = new KLineFrame(); frame.Canvas = this.Canvas; frame.ChartBorder = border; frame.Identify = id; //窗口序号 if (this.ModifyIndexDialog) frame.ModifyIndexEvent = this.ModifyIndexDialog.DoModal; //绑定菜单事件 if (this.ChangeIndexDialog) frame.ChangeIndexEvent = this.ChangeIndexDialog.DoModal; frame.HorizontalMax = 20; frame.HorizontalMin = 10; frame.YSplitOperator = new FrameSplitY(); frame.YSplitOperator.LanguageID = this.LanguageID; frame.YSplitOperator.FrameSplitData = this.FrameSplitData.get('double'); frame.YSplitOperator.Frame = frame; frame.YSplitOperator.ChartBorder = border; frame.XSplitOperator = new FrameSplitKLineX(); frame.XSplitOperator.Frame = frame; frame.XSplitOperator.ChartBorder = border; frame.XSplitOperator.ShowText = false; //K线数据绑定 var xPointCouont = this.Frame.SubFrame[0].Frame.XPointCount; frame.XPointCount = xPointCouont; frame.Data = this.ChartPaint[0].Data; for (var j = frame.HorizontalMin; j <= frame.HorizontalMax; j += 1) { frame.HorizontalInfo[j] = new CoordinateInfo(); frame.HorizontalInfo[j].Value = j; frame.HorizontalInfo[j].Message[1] = j.toString(); frame.HorizontalInfo[j].Font = "14px 微软雅黑"; } var subFrame = new SubFrameItem(); subFrame.Frame = frame; subFrame.Height = 10; return subFrame; } //创建主图K线画法 this.CreateMainKLine = function () { var kline = new ChartKLine(); kline.Canvas = this.Canvas; kline.ChartBorder = this.Frame.SubFrame[0].Frame.ChartBorder; kline.ChartFrame = this.Frame.SubFrame[0].Frame; kline.Name = "Main-KLine"; kline.DrawType = this.KLineDrawType; this.ChartPaint[0] = kline; this.TitlePaint[0] = new DynamicKLineTitlePainting(); this.TitlePaint[0].Frame = this.Frame.SubFrame[0].Frame; this.TitlePaint[0].Canvas = this.Canvas; this.TitlePaint[0].LanguageID = this.LanguageID; //主图叠加画法 var paint = new ChartOverlayKLine(); paint.Canvas = this.Canvas; paint.ChartBorder = this.Frame.SubFrame[0].Frame.ChartBorder; paint.ChartFrame = this.Frame.SubFrame[0].Frame; paint.Name = "Overlay-KLine"; paint.DrawType = this.KLineDrawType; this.OverlayChartPaint[0] = paint; } //绑定主图K线数据 this.BindMainData = function (hisData, showCount) { this.ChartPaint[0].Data = hisData; this.ChartPaint[0].Symbol = this.Symbol; if (this.KLineSize) { if (this.KLineSize.DataWidth==null) { showCount=this.Frame.SubFrame[0].Frame.XPointCount-this.RightSpaceCount; } else { var obj=this.Frame.SetDataWidth(this.KLineSize.DataWidth); showCount=obj.XPointCount-this.RightSpaceCount; this.KLineSize.DataWidth=null; } } for (var i in this.Frame.SubFrame) { var item = this.Frame.SubFrame[i].Frame; item.XPointCount = showCount + this.RightSpaceCount; item.Data = this.ChartPaint[0].Data; item.XSplitOperator.Symbol = this.Symbol; item.XSplitOperator.Period = this.Period; } this.TitlePaint[0].Data = this.ChartPaint[0].Data; //动态标题 this.TitlePaint[0].Symbol = this.Symbol; this.TitlePaint[0].Name = this.Name; this.TitlePaint[0].Period = this.Period; this.ChartCorssCursor.StringFormatX.Data = this.ChartPaint[0].Data; //十字光标 this.Frame.Data = this.ChartPaint[0].Data; this.OverlayChartPaint[0].MainData = this.ChartPaint[0].Data; //K线叠加 var dataOffset = hisData.Data.length - showCount; if (dataOffset < 0) dataOffset = 0; this.ChartPaint[0].Data.DataOffset = dataOffset; this.ChartCorssCursor.StringFormatY.Symbol = this.Symbol; this.CursorIndex = showCount; if (this.CursorIndex + dataOffset >= hisData.Data.length) this.CursorIndex = hisData.Data.length - 1 - dataOffset; if (this.CursorIndex < 0) this.CursorIndex = 0; //不一定对啊 } this.UpdateMainData = function (hisData, lastDataCount) //更新主图数据(不会放大缩小数据) { var frameHisdata = null; if (!this.Frame.Data) frameHisdata = this.Frame.Data; else if (this.Frame.SubFrame && this.Frame.SubFrame[0]) frameHisdata = this.Frame.SubFrame[0].Frame.Data; if (!frameHisdata) return; var xPointCount=this.Frame.SubFrame[0].Frame.XPointCount; //当前一屏能显示的数据个数 var newDataCount = 0; if (lastDataCount > 0 && hisData.Data.length > lastDataCount) { newDataCount = hisData.Data.length - lastDataCount; JSConsole.Chart.Log(`[KLineChartContainer::UpdateMainData] [count=${lastDataCount}->${hisData.Data.length}], [newDataCount=${newDataCount}]`); } this.ChartPaint[0].Data = hisData; this.ChartPaint[0].Symbol = this.Symbol; if (hisData.Data.length>xPointCount) //不满一屏的, 不需要调整索引 this.ChartPaint[0].Data.DataOffset = frameHisdata.DataOffset + newDataCount; //加上数据增加的个数 for (var i in this.Frame.SubFrame) { var item = this.Frame.SubFrame[i].Frame; item.Data = this.ChartPaint[0].Data; if (i==0) { item.YSplitOperator.Symbol = this.Symbol; item.YSplitOperator.Data = this.ChartPaint[0].Data; //K线数据 item.YSplitOperator.Period = this.Period; //周期 } } this.TitlePaint[0].Data = this.ChartPaint[0].Data; //动态标题 this.TitlePaint[0].Symbol = this.Symbol; this.TitlePaint[0].Name = this.Name; this.ChartCorssCursor.StringFormatX.Data = this.ChartPaint[0].Data; //十字光标 this.Frame.Data = this.ChartPaint[0].Data; for (var i in this.OverlayChartPaint) //主图股票数据绑定到叠加股票上 { var item = this.OverlayChartPaint[i]; item.MainData = this.ChartPaint[0].Data; } this.ChartCorssCursor.StringFormatY.Symbol = this.Symbol; } //创建指定窗口指标 this.CreateWindowIndex = function (windowIndex) { this.WindowIndex[windowIndex].Create(this, windowIndex); } this.BindIndexData = function (windowIndex, hisData) { if (!this.WindowIndex[windowIndex]) return; if (typeof (this.WindowIndex[windowIndex].RequestData) == "function") //数据需要另外下载的. { this.WindowIndex[windowIndex].RequestData(this, windowIndex, hisData); return; } if (typeof (this.WindowIndex[windowIndex].ExecuteScript) == 'function') //脚本指标 { this.WindowIndex[windowIndex].ExecuteScript(this, windowIndex, hisData); return; } this.WindowIndex[windowIndex].BindData(this, windowIndex, hisData); } //执行指示(专家指示 五彩K线) this.BindInstructionIndexData = function (hisData) { if (this.ColorIndex && typeof (this.ColorIndex.ExecuteScript) == 'function') //五彩K线 { this.ColorIndex.ExecuteScript(this, 0, hisData); } if (this.TradeIndex && typeof (this.TradeIndex.ExecuteScript) == 'function') //交易指标 { this.TradeIndex.ExecuteScript(this, 0, hisData); } } //获取子窗口的所有画法 this.GetChartPaint = function (windowIndex) { var paint = new Array(); for (var i in this.ChartPaint) { if (i == 0) continue; //第1个K线数据除外 var item = this.ChartPaint[i]; if (item.ChartFrame == this.Frame.SubFrame[windowIndex].Frame) paint.push(item); } return paint; } this.AutoUpdateEvent = function (bStart) //自定更新事件, 是给websocket使用 { var eventID = bStart ? JSCHART_EVENT_ID.RECV_START_AUTOUPDATE : JSCHART_EVENT_ID.RECV_STOP_AUTOUPDATE; if (!this.mapEvent.has(eventID)) return; var self = this; var event = this.mapEvent.get(eventID); var data = { Stock: { Symbol: this.Symbol, Name: this.Name, Right: this.Right, Period: this.Period } }; if (bStart) { data.Callback = function (data) //数据到达更新回调 { if (ChartData.IsDayPeriod(self.Period, true)) self.RecvRealtimeData(data); else if (ChartData.IsMinutePeriod(self.Period, true)) self.RecvMinuteRealtimeData(data); else if (ChartData.IsSecondPeriod(self.Period)) self.RecvMinuteRealtimeData(data); } } event.Callback(event, data, this); } this.RequestHistoryData = function () { var self = this; this.CancelAutoUpdate(); this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle); this.ChartSplashPaint.EnableSplash(true); this.ResetDragDownload(); this.Draw(); if (this.NetworkFilter) { var obj = { Name: 'KLineChartContainer::RequestHistoryData', //类名:: Explain: '日K数据', Request: { Url: self.KLineApiUrl, Type: 'POST', Data: { symbol: self.Symbol, count: self.MaxReqeustDataCount, field: ["name", "symbol", "yclose", "open", "price", "high", "low", "vol"] } }, Self: this, PreventDefault: false }; this.NetworkFilter(obj, function (data) { self.ChartSplashPaint.EnableSplash(false); self.RecvHistoryData(data); self.AutoUpdateEvent(true); self.AutoUpdate(); }); if (obj.PreventDefault == true) return; //已被上层替换,不调用默认的网络请求 } wx.request({ url: this.KLineApiUrl, data: { "field": ["name","symbol","yclose","open","price","high","low","vol"], "symbol": self.Symbol, "start": -1, "count": self.MaxReqeustDataCount }, method: 'POST', dataType: 'json', success: function (data) { self.ChartSplashPaint.EnableSplash(false); self.RecvHistoryData(data); self.AutoUpdateEvent(true); self.AutoUpdate(); } }); } this.RecvHistoryData = function (recvData) { var data = recvData.data; var aryDayData = KLineChartContainer.JsonDataToHistoryData(data); //原始数据 var sourceData = new ChartData(); sourceData.Data = aryDayData; sourceData.DataType = 0; //0=日线数据 1=分钟数据 sourceData.Symbol = data.symbol; this.SourceData = sourceData; if (this.BeforeBindMainData) this.BeforeBindMainData("RecvHistoryData"); //显示的数据 var bindData = new ChartData(); bindData.Data = aryDayData; bindData.Right = this.Right; bindData.Period = this.Period; bindData.DataType = 0; if (bindData.Right > 0 && !this.IsApiPeriod) //复权 { var rightData = bindData.GetRightDate(bindData.Right); bindData.Data = rightData; } if (ChartData.IsDayPeriod(bindData.Period, false) && !this.IsApiPeriod) //周期数据 { var periodData = bindData.GetPeriodData(bindData.Period); bindData.Data = periodData; } //绑定数据 this.Symbol = data.symbol; this.Name = data.name; this.BindMainData(bindData, this.PageSize); if (this.AfterBindMainData) this.AfterBindMainData("RecvHistoryData"); this.Frame.SetSizeChage(true); //数据到达通知坐标框架 this.BindInstructionIndexData(bindData); //执行指示脚本 var firstSubFrame; //主窗口 for (var i = 0; i < this.Frame.SubFrame.length; ++i) //执行指标 { if (i == 0) firstSubFrame = this.Frame.SubFrame[i].Frame; this.BindIndexData(i, bindData); } if (firstSubFrame && firstSubFrame.YSplitOperator) { firstSubFrame.YSplitOperator.Symbol = this.Symbol; //绑定代码 firstSubFrame.YSplitOperator.Data = this.ChartPaint[0].Data; //K线数据 } //请求叠加数据 (主数据下载完再下载)) this.ReqeustKLineInfoData(); this.RequestOverlayHistoryData(); //刷新画图 this.UpdataDataoffset(); //更新数据偏移 this.UpdatePointByCursorIndex(); //更新十字光标位子 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); if (this.mapEvent.has(JSCHART_EVENT_ID.RECV_HISTROY_DATA)) { var event = this.mapEvent.get(JSCHART_EVENT_ID.RECV_HISTROY_DATA); var data = { HistoryData: bindData, Stock: { Symbol: this.Symbol, Name: this.Name } } event.Callback(event, data, this); } else //老的回调暂时保留 { if (typeof (this.UpdateUICallback) == 'function') this.UpdateUICallback('RecvHistroyData', this); //单词拼写错误, 请使用下面的回调 if (typeof (this.UpdateUICallback) == 'function') this.UpdateUICallback('RecvHistoryData', this); } } this.ReqeustHistoryMinuteData = function () { var self = this; this.CancelAutoUpdate(); this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle); this.ChartSplashPaint.EnableSplash(true); this.ResetDragDownload(); this.Draw(); if (this.NetworkFilter) { var obj = { Name: 'KLineChartContainer::ReqeustHistoryMinuteData', //类名 Explain: '1分钟K线数据', Request: { Url: self.MinuteKLineApiUrl, Type: 'POST', Data: { symbol: self.Symbol, count: self.MaxRequestMinuteDayCount, field: ["name", "symbol", "yclose", "open", "price", "high", "low", "vol"] } }, Self: this, PreventDefault: false }; this.NetworkFilter(obj, function (data) { self.ChartSplashPaint.EnableSplash(false); self.RecvMinuteHistoryData(data); self.AutoUpdateEvent(true); self.AutoUpdate(); }); if (obj.PreventDefault == true) return; //已被上层替换,不调用默认的网络请求 } wx.request({ url: this.MinuteKLineApiUrl, data: { "field": ["name","symbol","yclose","open","price","high","low","vol"], "symbol": self.Symbol, "start": -1, "count": self.MaxRequestMinuteDayCount }, method: 'POST', dataType: "json", success: function (data) { self.ChartSplashPaint.EnableSplash(false); self.RecvMinuteHistoryData(data); self.AutoUpdateEvent(true); self.AutoUpdate(); } }); } this.RecvMinuteHistoryData = function (recvData) { var data = recvData.data; var aryDayData = KLineChartContainer.JsonDataToMinuteHistoryData(data); //原始数据 var sourceData = new ChartData(); sourceData.Data = aryDayData; sourceData.DataType = 1; //0=日线数据 1=分钟数据 sourceData.Symbol = data.symbol; this.SourceData = sourceData; if (this.BeforeBindMainData) this.BeforeBindMainData("RecvMinuteHistoryData"); //显示的数据 var bindData = new ChartData(); bindData.Data = aryDayData; bindData.Right = this.Right; bindData.Period = this.Period; bindData.DataType = 1; bindData.Symbol = data.symbol; if (ChartData.IsMinutePeriod(bindData.Period, false) && !this.IsApiPeriod) //周期数据 { var periodData = sourceData.GetPeriodData(bindData.Period); bindData.Data = periodData; } //绑定数据 this.Symbol = data.symbol; this.Name = data.name; this.BindMainData(bindData, this.PageSize); if (this.AfterBindMainData) this.AfterBindMainData("RecvMinuteHistoryData"); this.Frame.SetSizeChage(true); this.BindInstructionIndexData(bindData); //执行指示脚本 var firstSubFrame; //主窗口 for (var i = 0; i < this.Frame.SubFrame.length; ++i) { if (i == 0) firstSubFrame = this.Frame.SubFrame[i].Frame; this.BindIndexData(i, bindData); } if (firstSubFrame && firstSubFrame.YSplitOperator) { firstSubFrame.YSplitOperator.Symbol = this.Symbol; //绑定代码 firstSubFrame.YSplitOperator.Data = this.ChartPaint[0].Data; //K线数据 } this.OverlayChartPaint[0].Data = null; //分钟数据不支持叠加 清空 //刷新画图 this.UpdataDataoffset(); //更新数据偏移 this.UpdatePointByCursorIndex(); //更新十字光标位子 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); if (this.mapEvent.has(JSCHART_EVENT_ID.RECV_HISTROY_DATA)) { var event = this.mapEvent.get(JSCHART_EVENT_ID.RECV_HISTROY_DATA); var data = { HistoryData: bindData, Stock: { Symbol: this.Symbol, Name: this.Name } } event.Callback(event, data, this); } else { if (typeof (this.UpdateUICallback) == 'function') this.UpdateUICallback('RecvMinuteHistoryData', this); } } //请求实时行情数据 this.RequestRealtimeData = function () { var self = this; if (this.NetworkFilter) { var obj = { Name: 'KLineChartContainer::RequestRealtimeData', //类名::函数名 Explain: '当天最新日线数据', Request: { Url: self.RealtimeApiUrl, Data: { symbol: [self.Symbol], field: ["name", "symbol", "yclose", "open", "price", "high", "low", "vol", "amount", "date", "time"] }, Type: 'POST' }, Self: this, PreventDefault: false }; this.NetworkFilter(obj, function (data) { self.RecvRealtimeData(data); self.AutoUpdate(); }); if (obj.PreventDefault == true) return; //已被上层替换,不调用默认的网络请求 } wx.request({ url: this.RealtimeApiUrl, data: { "field": ["name","symbol","yclose","open","price","high","low","vol","amount","date","time"], "symbol": [self.Symbol], "start": -1 }, method: 'POST', dataType: "json", async: true, success: function (data) { self.RecvRealtimeData(data); self.AutoUpdate(); } }); } this.RecvRealtimeData = function (recvdata) { if (this.IsOnTouch == true) return; //正在操作中不更新数据 var data=recvdata.data; if (!data || !data.stock || !data.stock[0] || this.Symbol != data.stock[0].symbol) { JSConsole.Chart.Log('[KLineChartContainer::RecvRealtimeData] recvdata error', recvdata); return; } var realtimeData = KLineChartContainer.JsonDataToRealtimeData(data); var item = this.SourceData.Data[this.SourceData.Data.length - 1]; //最新的一条数据 var lastDataCount = this.GetHistoryDataCount(); //保存下上一次的数据个数 if (item.Date == realtimeData.Date) //实时行情数据更新 { //JSConsole.Chart.Log('[KLineChartContainer::RecvRealtimeData] update kline by minute data', realtimeData); item.Close = realtimeData.Close; item.High = realtimeData.High; item.Low = realtimeData.Low; item.Vol = realtimeData.Vol; item.Amount = realtimeData.Amount; } else if (item.Date < realtimeData.Date) //新增加数据 { JSConsole.Chart.Log('[KLineChartContainer::RecvRealtimeData] insert kline by minute data', realtimeData); var newItem = new HistoryData(); newItem.YClose = realtimeData.YClose; newItem.Open = realtimeData.Open; newItem.Close = realtimeData.Close; newItem.High = realtimeData.High; newItem.Low = realtimeData.Low; newItem.Vol = realtimeData.Vol; newItem.Amount = realtimeData.Amount; newItem.Date = realtimeData.Date; //没有前收盘就用上一个数据的收盘价 if (!IFrameSplitOperator.IsNumber(newItem.YClose) && this.SourceData.Data.length>0) newItem.YClose=this.SourceData.Data[this.SourceData.Data.length-1].YClose; this.SourceData.Data.push(newItem); } else { return; } var bindData = new ChartData(); bindData.Data = this.SourceData.Data; bindData.Period = this.Period; bindData.Right = this.Right; bindData.DataType = this.SourceData.DataType; bindData.Symbol = this.Symbol; if (bindData.Right > 0 && ChartData.IsDayPeriod(bindData.Period,true) && !this.IsApiPeriod) //复权(日线数据才复权) { var rightData = bindData.GetRightDate(bindData.Right); bindData.Data = rightData; } if (!this.IsApiPeriod) { if (ChartData.IsDayPeriod(bindData.Period, false) || ChartData.IsMinutePeriod(bindData.Period, false)) //周期数据 (0= 日线,4=1分钟线 不需要处理) { var periodData = bindData.GetPeriodData(bindData.Period); bindData.Data = periodData; } } //绑定数据 this.UpdateMainData(bindData, lastDataCount); this.Frame.SetSizeChage(true); this.BindInstructionIndexData(bindData); //执行指示脚本 for (var i = 0; i < this.Frame.SubFrame.length; ++i) { this.BindIndexData(i, bindData); } //刷新画图 this.UpdataDataoffset(); //更新数据偏移 this.UpdatePointByCursorIndex(); //更新十字光标位子 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); this.SendKLineUpdateEvent(bindData); } this.GetHistoryDataCount = function () { var frameHisdata = null; if (!this.Frame.Data) frameHisdata = this.Frame.Data; else if (this.Frame.SubFrame && this.Frame.SubFrame[0]) frameHisdata = this.Frame.SubFrame[0].Frame.Data; if (!frameHisdata) return -1; var lastDataCount = frameHisdata.Data.length; //上一个的数据长度 return lastDataCount; } this.RequestMinuteRealtimeData = function () { var self = this; if (this.NetworkFilter) { var obj = { Name: 'KLineChartContainer::RequestMinuteRealtimeData', //类名:: Explain: '当天1分钟K线数据', Request: { Url: self.RealtimeApiUrl, Data: { symbol: [self.Symbol], field: ["name", "symbol", "price", "yclose", "minutecount", "minute", "date", "time"] }, Type: 'POST' }, Self: this, PreventDefault: false }; this.NetworkFilter(obj, function (data) { self.RecvMinuteRealtimeData(data); self.AutoUpdate(); }); if (obj.PreventDefault == true) return; //已被上层替换,不调用默认的网络请求 } wx.request({ url: this.RealtimeApiUrl, data: { "field": ["name", "symbol", "price", "yclose", "minutecount", "minute", "date", "time"], "symbol": [self.Symbol], "start": -1 }, method: 'POST', dataType: "json", async: true, success: function (data) { self.RecvMinuteRealtimeData(data); self.AutoUpdate(); } }); } this.SetSourceDatatLimit = function (aryLimit) { this.SourceDataLimit = new Map(); for (var i in aryLimit) { var item = aryLimit[i]; this.SourceDataLimit.set(item.Period, item.MaxCount); //每个周期缓存数据最大个数 key=周期 value=最大个数 JSConsole.Chart.Log(`[KLineChartContainer::SetSourceDatatLimit] Period=${item.Period}, MaxCount=${item.MaxCount}`); } } this.ReduceSourceData = function () { if (!this.SourceDataLimit) return; if (!this.SourceDataLimit.has(this.Period)) return; var limitCount = this.SourceDataLimit.get(this.Period); if (limitCount < 50) return; var frameHisdata = null; if (!this.Frame.Data) frameHisdata = this.Frame.Data; else if (this.Frame.SubFrame && this.Frame.SubFrame[0]) frameHisdata = this.Frame.SubFrame[0].Frame.Data; if (!frameHisdata) return; var dataOffset = frameHisdata.DataOffset; var removeCount = 0; while (this.SourceData.Data.length > limitCount) { this.SourceData.Data.shift(); --dataOffset; ++removeCount; } if (removeCount > 0) { if (dataOffset < 0) dataOffset = 0; frameHisdata.DataOffset = dataOffset; JSConsole.Chart.Log(`[KLineChartContainer::ReduceSourceData] remove data ${removeCount}, dataOffset=${dataOffset}`); } } this.RecvMinuteRealtimeData = function (recvData) { var data=recvData.data; if (this.IsOnTouch == true) return; //正在操作中不更新数据 if (data.ver == 2.0) { this.RecvMinuteRealtimeDataV2(data); //v2.0数据版本 return; } if (!data.stock || !data.stock[0] || this.Symbol != data.stock[0].symbol) return; var realtimeData = KLineChartContainer.JsonDataToMinuteRealtimeData(data); if (!realtimeData) return; if (this.IsApiPeriod) this.ReduceSourceData(); //减少数据 var lastDataCount = this.GetHistoryDataCount(); //保存下上一次的数据个数 var lastSourceDataCount = this.SourceData.Data.length; if (!this.SourceData.MergeMinuteData(realtimeData)) return; JSConsole.Chart.Log(`[KLineChartContainer::RecvMinuteRealtimeData] update kline by 1 minute data [${lastSourceDataCount}->${this.SourceData.Data.length}]`); var bindData = new ChartData(); bindData.Data = this.SourceData.Data; bindData.Period = this.Period; bindData.Right = this.Right; bindData.DataType = this.SourceData.DataType; bindData.Symbol = this.Symbol; if (bindData.Right > 0 && ChartData.IsDayPeriod(bindData.Period,true) && !this.IsApiPeriod) //复权(日线数据才复权) { var rightData = bindData.GetRightDate(bindData.Right); bindData.Data = rightData; } if (!this.IsApiPeriod) { if (ChartData.IsDayPeriod(bindData.Period, false) || ChartData.IsMinutePeriod(bindData.Period, false)) //周期数据 (0= 日线,4=1分钟线 不需要处理) { var periodData = bindData.GetPeriodData(bindData.Period); bindData.Data = periodData; } } //绑定数据 this.UpdateMainData(bindData, lastDataCount); this.Frame.SetSizeChage(true); this.BindInstructionIndexData(bindData); //执行指示脚本 for (var i = 0; i < this.Frame.SubFrame.length; ++i) { this.BindIndexData(i, bindData); } //刷新画图 this.UpdataDataoffset(); //更新数据偏移 this.UpdatePointByCursorIndex(); //更新十字光标位子 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); this.SendKLineUpdateEvent(bindData); } this.RecvMinuteRealtimeDataV2 = function (data) //新版本的 { if (this.IsOnTouch == true) return; //正在操作中不更新数据 var aryMinuteData = KLineChartContainer.JsonDataToMinuteHistoryData(data); if (!aryMinuteData || aryMinuteData.length <= 0) return; if (this.IsApiPeriod) this.ReduceSourceData(); //减少数据 var lastDataCount = this.GetHistoryDataCount(); //保存下上一次的数据个数 if (!this.SourceData.MergeMinuteData(aryMinuteData)) return; JSConsole.Chart.Log(`[KLineChartContainer::RecvMinuteRealtimeDataV2] update kline by 1 minute data [${lastDataCount}->${this.SourceData.Data.length}]`); var bindData = new ChartData(); bindData.Data = this.SourceData.Data; bindData.Period = this.Period; bindData.Right = this.Right; bindData.DataType = this.SourceData.DataType; bindData.Symbol = this.Symbol; if (bindData.Right > 0 && ChartData.IsDayPeriod(bindData.Period, true) && !this.IsApiPeriod) //复权(日线数据才复权) { var rightData = bindData.GetRightDate(bindData.Right); bindData.Data = rightData; } if ((ChartData.IsDayPeriod(bindData.Period, false) || ChartData.IsMinutePeriod(bindData.Period, false)) && !this.IsApiPeriod) //周期数据 (0= 日线,4=1分钟线 不需要处理) { var periodData = bindData.GetPeriodData(bindData.Period); bindData.Data = periodData; } //绑定数据 this.UpdateMainData(bindData, lastDataCount); this.Frame.SetSizeChage(true); this.BindInstructionIndexData(bindData); //执行指示脚本 for (var i = 0; i < this.Frame.SubFrame.length; ++i) { this.BindIndexData(i, bindData); } //刷新画图 this.UpdataDataoffset(); //更新数据偏移 this.UpdatePointByCursorIndex(); //更新十字光标位子 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); this.SendKLineUpdateEvent(bindData); } this.SendKLineUpdateEvent = function (bindData) { var event = this.GetEvent(JSCHART_EVENT_ID.RECV_KLINE_UPDATE_DATA); if (event && event.Callback) { var data = { HistoryData: bindData, Stock: { Symbol: this.Symbol, Name: this.Name } } event.Callback(event, data, this); return true; } return false; } //周期切换 this.ChangePeriod = function (period, option) { var isChangeKLineDrawType = false; var right=null; //复权 if (option && option.KLine) { if (IFrameSplitOperator.IsNumber(option.KLine.DrawType)) isChangeKLineDrawType = true; if (IFrameSplitOperator.IsNumber(option.KLine.Right)) right=option.KLine.Right; }; if (this.Period == period) { if (isChangeKLineDrawType) this.ChangeKLineDrawType(option.KLine.DrawType); return; } if (isChangeKLineDrawType) this.ChangeKLineDrawType(option.KLine.DrawType, false); //切换K线类型, 不重绘 var isDataTypeChange = true; if (this.SourceData) { var isDataTypeChange=false; if (period > CUSTOM_DAY_PERIOD_START && period <= CUSTOM_DAY_PERIOD_END) { if (this.SourceData.DataType != 0) isDataTypeChange = true; } else if ((period > CUSTOM_MINUTE_PERIOD_START && period <= CUSTOM_MINUTE_PERIOD_END) || (period > CUSTOM_SECOND_PERIOD_START && period <= CUSTOM_SECOND_PERIOD_END)) { if (this.SourceData.DataType != 1) isDataTypeChange = true; } else { switch (period) { case 0: //日线 case 1: //周 case 2: //月 case 3: //年 case 21: //双周 if (this.SourceData.DataType != 0) isDataTypeChange = true; break; case 4: //1分钟 case 5: //5分钟 case 6: //15分钟 case 7: //30分钟 case 8: //60分钟 case 11: //2小时 case 12: //4小时 if (this.SourceData.DataType != 1) isDataTypeChange = true; break; } } } this.Period = period; if (right!=null) this.Right=right; if (isDataTypeChange == false && !this.IsApiPeriod) { this.Update(); return; } if (ChartData.IsDayPeriod(this.Period, true)) { this.CancelAutoUpdate(); //先停止更新 this.AutoUpdateEvent(false); this.RequestHistoryData(); //请求日线数据 //this.ReqeustKLineInfoData(); } else if (ChartData.IsMinutePeriod(this.Period, true) || ChartData.IsSecondPeriod(this.Period)) { this.CancelAutoUpdate(); //先停止更新 this.AutoUpdateEvent(false); this.ReqeustHistoryMinuteData(); //请求分钟数据 } } //复权切换 this.ChangeRight = function (right) { if (IsIndexSymbol(this.Symbol)) return; //指数没有复权 if (right < 0 || right > 2) return; if (this.Right == right) return; this.Right = right; if (!this.IsApiPeriod) { this.Update(); return; } else { if (ChartData.IsDayPeriod(this.Period, true)) { this.CancelAutoUpdate(); //先停止更新 this.AutoUpdateEvent(false); this.RequestHistoryData(); //请求日线数据 //this.ReqeustKLineInfoData(); } else if (ChartData.IsMinutePeriod(this.Period, true) || ChartData.IsSecondPeriod(this.Period)) { this.CancelAutoUpdate(); //先停止更新 this.AutoUpdateEvent(false); this.ReqeustHistoryMinuteData(); //请求分钟数据 } } } //删除某一个窗口的指标 this.DeleteIndexPaint = function (windowIndex) { let paint = new Array(); //踢出当前窗口的指标画法 for (let i in this.ChartPaint) { let item = this.ChartPaint[i]; if (i == 0 || item.ChartFrame != this.Frame.SubFrame[windowIndex].Frame) paint.push(item); } this.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin = null; //清空指定最大最小值 this.Frame.SubFrame[windowIndex].Frame.IsLocked = false; //解除上锁 this.Frame.SubFrame[windowIndex].Frame.YSplitScale = null; //清空固定刻度 this.ChartPaint = paint; //清空东条标题 var titleIndex = windowIndex + 1; this.TitlePaint[titleIndex].Data = []; this.TitlePaint[titleIndex].Title = null; } this.ShowKLine = function (isShow) //显示隐藏主图K线 { if (this.ChartPaint.length <= 0 || !this.ChartPaint[0]) return; this.ChartPaint[0].IsShow = isShow; } this.SetInstructionData = function (type, instructionData) //设置指示数据 { if (this.ChartPaint.length <= 0 || !this.ChartPaint[0]) return; if (type == 2) //五彩K线 { this.ChartPaint[0].ColorData = instructionData.Data; } else if (type == 1) //专家指示 { this.ChartPaint[0].TradeData = { Sell: instructionData.Sell, Buy: instructionData.Buy }; } } this.ChangeInstructionIndex = function (indexName) { let scriptData = new JSCommonIndexScript.JSIndexScript(); let indexInfo = scriptData.Get(indexName); if (!indexInfo) return; if (indexInfo.InstructionType != 1 && indexInfo.InstructionType != 2) return; this.ChangeInstructionScriptIndex(indexInfo); } this.ChangeInstructionScriptIndex = function (indexData) { if (indexData.InstructionType == 1) //交易系统 { this.TradeIndex = new ScriptIndex(indexData.Name, indexData.Script, indexData.Args, indexData); //脚本执行 } else if (indexData.InstructionType == 2) //五彩K线 { this.ColorIndex = new ScriptIndex(indexData.Name, indexData.Script, indexData.Args, indexData); //脚本执行 } else { return; } var bindData = this.ChartPaint[0].Data; this.BindInstructionIndexData(bindData); this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } this.CancelInstructionIndex = function () //取消指示数据 { if (this.ChartPaint.length <= 0 || !this.ChartPaint[0]) return; this.ColorIndex=null; this.TradeIndex=null; this.ChartPaint[0].ColorData = null; //五彩K线数据取消掉 this.ChartPaint[0].TradeData = null; //交易系统数据取消 this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } //切换成 脚本指标 this.ChangeScriptIndex = function (windowIndex, indexData) { this.DeleteIndexPaint(windowIndex); this.WindowIndex[windowIndex] = new ScriptIndex(indexData.Name, indexData.Script, indexData.Args, indexData); //脚本执行 var bindData = this.ChartPaint[0].Data; this.BindIndexData(windowIndex, bindData); //执行脚本 this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } //切换api指标 this.ChangeAPIIndex = function (windowIndex, indexData) { this.DeleteIndexPaint(windowIndex); //使用API挂接指标数据 API:{ Name:指标名字, Script:指标脚本可以为空, Args:参数可以为空, Url:指标执行地址 } var apiItem = indexData.API; this.WindowIndex[windowIndex] = new APIScriptIndex(apiItem.Name, apiItem.Script, apiItem.Args, indexData); var bindData = this.ChartPaint[0].Data; this.BindIndexData(windowIndex, bindData); //执行脚本 this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } //切换指标 指定切换窗口指标 this.ChangeIndex = function (windowIndex, indexName, option) { if (option && option.API) //切换api指标 return this.ChangeAPIIndex(windowIndex, option); var indexItem = JSIndexMap.Get(indexName); if (!indexItem) { //查找系统指标 let scriptData = new JSCommonIndexScript.JSIndexScript(); let indexInfo = scriptData.Get(indexName); if (!indexInfo) return; if (indexInfo.IsMainIndex) { windowIndex = 0; //主图指标只能在主图显示 } else { if (windowIndex == 0) windowIndex = 1; //幅图指标,不能再主图显示 } let indexData = indexInfo; if (option) { if (option.FloatPrecision >= 0) indexData.FloatPrecision = option.FloatPrecision; if (option.StringFormat > 0) indexData.StringFormat = option.StringFormat; if (option.Args) indexData.Args = option.Args; } return this.ChangeScriptIndex(windowIndex, indexData); } //主图指标 if (indexItem.IsMainIndex) { if (windowIndex > 0) windowIndex = 0; //主图指标只能在主图显示 } else { if (windowIndex == 0) windowIndex = 1; //幅图指标,不能再主图显示 } var paint = new Array(); //踢出当前窗口的指标画法 for (var i in this.ChartPaint) { var item = this.ChartPaint[i]; if (i == 0 || item.ChartFrame != this.Frame.SubFrame[windowIndex].Frame) paint.push(item); } //清空指定最大最小值 this.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin = null; this.Frame.SubFrame[windowIndex].Frame.YSplitScale=null; this.ChartPaint = paint; //清空东条标题 var titleIndex = windowIndex + 1; this.TitlePaint[titleIndex].Data = []; this.TitlePaint[titleIndex].Title = null; this.WindowIndex[windowIndex] = indexItem.Create(); this.CreateWindowIndex(windowIndex); var bindData = this.ChartPaint[0].Data; this.BindIndexData(windowIndex, bindData); this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } this.ChangeKLineDrawType = function (drawType, isDraw) { if (this.KLineDrawType == drawType) return; this.KLineDrawType = drawType; for (var i in this.ChartPaint) { var item = this.ChartPaint[i]; if (i == 0) item.DrawType = this.KLineDrawType; else if (item.ClassName == 'ChartVolStick') item.KLineDrawType = this.KLineDrawType } if (this.OverlayChartPaint[0]) this.OverlayChartPaint[0].DrawType = this.KLineDrawType; //叠加K线修改 if (isDraw == false) return; this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } //获取当天的显示的指标 this.GetIndexInfo = function () { var aryIndex = []; for (var i in this.WindowIndex) { var item = this.WindowIndex[i]; var info = { Name: item.Name }; if (item.ID) info.ID = item.ID; aryIndex.push(info); } return aryIndex; } this.ChangeIndexTemplate = function (option) //切换指标模板 可以设置指标窗口个数 每个窗口的指标 { if (!option.Windows) return; var count = option.Windows.length; if (count <= 0) return; var currentLength = this.Frame.SubFrame.length; var period=null, right=null; if (option.KLine) { if (IFrameSplitOperator.IsNumber(option.KLine.Period) && option.KLine.Period!=this.Period) period=option.KLine.Period; //周期 if (IFrameSplitOperator.IsNumber(option.KLine.Right) && option.KLine.Right!=this.Right) right=option.KLine.Right; //复权 } var bRefreshData= (period!=null || right!=null); //清空所有的指标图型 for (var i = 0; i < currentLength; ++i) { this.DeleteIndexPaint(i); var frame = this.Frame.SubFrame[i]; frame.YSpecificMaxMin = null; frame.IsLocked = false; frame.YSplitScale = null; } if (currentLength > count) { this.Frame.SubFrame.splice(count, currentLength - count); this.WindowIndex.splice(count, currentLength - count); } else { for (var i = currentLength; i < count; ++i) //创建新的指标窗口 { var subFrame = this.CreateSubFrameItem(i); this.Frame.SubFrame[i] = subFrame; var titlePaint = new DynamicChartTitlePainting(); titlePaint.Frame = this.Frame.SubFrame[i].Frame; titlePaint.Canvas = this.Canvas; titlePaint.LanguageID = this.LanguageID; this.TitlePaint[i + 1] = titlePaint; } } var systemScript = new JSCommonIndexScript.JSIndexScript(); var bindData = this.ChartPaint[0].Data; for (var i = 0; i < count; ++i) { var windowIndex = i; var item=option.Windows[i]; var frameItem=null; if(option.Frame && option.Frame.length>i) frameItem=option.Frame[i]; var titleIndex = windowIndex + 1; this.TitlePaint[titleIndex].Data = []; this.TitlePaint[titleIndex].Title = null; if (item.Script) //自定义指标 { this.WindowIndex[i]=new ScriptIndex(item.Name,item.Script,item.Args,item); //脚本执行 if (!bRefreshData) this.BindIndexData(windowIndex,bindData); //执行脚本 } else { var indexID = item.Index; var indexItem = JSIndexMap.Get(indexID); if (indexItem) { this.WindowIndex[i] = indexItem.Create(); this.CreateWindowIndex(windowIndex); if (!bRefreshData) this.BindIndexData(windowIndex, bindData); } else { var indexInfo = systemScript.Get(indexID); if (indexInfo) { var args = indexInfo.Args; if (option.Windows[i].Args) args = option.Windows[i].Args; let indexData = { Name: indexInfo.Name, Script: indexInfo.Script, Args: args, ID: indexID, //扩展属性 可以是空 KLineType: indexInfo.KLineType, YSpecificMaxMin: indexInfo.YSpecificMaxMin, YSplitScale: indexInfo.YSplitScale, FloatPrecision: indexInfo.FloatPrecision, Condition: indexInfo.Condition, OutName:indexInfo.OutName }; this.WindowIndex[i] = new ScriptIndex(indexData.Name, indexData.Script, indexData.Args, indexData); //脚本执行 if (!bRefreshData) this.BindIndexData(windowIndex, bindData); //执行脚本 } } } if (item.IndexParamSpace >= 0) this.Frame.SubFrame[i].Frame.IndexParamSpace = item.IndexParamSpace; if (item.IsDrawTitleBG==true) this.Frame.SubFrame[i].Frame.IsDrawTitleBG=item.IsDrawTitleBG; if (frameItem) { if (frameItem.SplitCount) this.Frame.SubFrame[i].Frame.YSplitOperator.SplitCount = frameItem.SplitCount; if (frameItem.IsShowBorder == false) this.Frame.SubFrame[i].Frame.IsShowBorder = frameItem.IsShowBorder; if (frameItem.IsShowXLine === false || frameItem.IsShowXLine ===true) this.Frame.SubFrame[i].Frame.IsShowXLine = frameItem.IsShowXLine; if (frameItem.IsShowYLine===false ||frameItem.IsShowYLine===true) this.Frame.SubFrame[i].Frame.IsShowYLine=frameItem.IsShowYLine; if (frameItem.IsShowLeftText === false || item.IsShowLeftText === true) this.Frame.SubFrame[i].Frame.IsShowYText[0] = frameItem.IsShowLeftText; //显示左边刻度 if (frameItem.IsShowRightText === false || item.IsShowRightText === true) this.Frame.SubFrame[i].Frame.IsShowYText[1] = frameItem.IsShowRightText; //显示右边刻度 } } //最后一个显示X轴坐标 for (var i = 0; i < this.Frame.SubFrame.length; ++i) { var item = this.Frame.SubFrame[i].Frame; if (i == this.Frame.SubFrame.length - 1) item.XSplitOperator.ShowText = true; else item.XSplitOperator.ShowText = false; } if (!bRefreshData) { this.UpdataDataoffset(); //更新数据偏移 this.Frame.SetSizeChage(true); this.ResetFrameXYSplit(); this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } else { this.Frame.SetSizeChage(true); if (period!=null) this.ChangePeriod(period, option); else if (right!=null) this.ChangeRight(right); } } this.RemoveIndexWindow=function(id) { JSConsole.Chart.Log('[KLineChartContainer::RemoveIndexWindow] remove id', id); if (id==0) return; if (!this.Frame.SubFrame) return; if (id>=this.Frame.SubFrame.length) return; var delFrame=this.Frame.SubFrame[id].Frame; this.DeleteIndexPaint(id); this.Frame.SubFrame.splice(id,1); this.WindowIndex.splice(id,1); this.TitlePaint.splice(id+1,1); //删除对应的动态标题 for(var i=0;i0) { var aryDrawPicture=[]; for(var i=0;i 0 && ChartData.IsDayPeriod(bindData.Period, true)) //复权(日线数据才复权) { var rightData = bindData.GetRightDate(bindData.Right); bindData.Data = rightData; } if (ChartData.IsDayPeriod(bindData.Period, false) || ChartData.IsMinutePeriod(bindData.Period, false)) //周期数据 (0= 日线,4=1分钟线 不需要处理)) { var periodData = bindData.GetPeriodData(bindData.Period); bindData.Data = periodData; } //绑定数据 this.BindMainData(bindData, this.PageSize); if (this.AfterBindMainData) this.AfterBindMainData("Update"); for (var i = 0; i < this.Frame.SubFrame.length; ++i) { this.BindIndexData(i, bindData); } //叠加数据周期调整 if (this.OverlayChartPaint[0].SourceData) { if (ChartData.IsMinutePeriod(this.Period, true)) //分钟不支持 清空掉 { this.OverlayChartPaint[0].Data = null; } else { var bindData = new ChartData(); bindData.Data = this.OverlayChartPaint[0].SourceData.Data; bindData.Period = this.Period; bindData.Right = this.Right; if (bindData.Right > 0 && !IsIndexSymbol(this.OverlayChartPaint[0].Symbol)) //复权数据 { var rightData = bindData.GetRightDate(bindData.Right); bindData.Data = rightData; } var aryOverlayData = this.SourceData.GetOverlayData(bindData.Data); //和主图数据拟合以后的数据 bindData.Data = aryOverlayData; if (ChartData.IsDayPeriod(bindData.Period, false)) //周期数据 { var periodData = bindData.GetPeriodData(bindData.Period); bindData.Data = periodData; } this.OverlayChartPaint[0].Data = bindData; } } this.ReqeustKLineInfoData(); //刷新画图 this.UpdataDataoffset(); //更新数据偏移 this.UpdatePointByCursorIndex(); //更新十字光标位子 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } //切换股票代码 this.ChangeSymbol = function (symbol) { this.CancelAutoUpdate(); //先停止更新 this.AutoUpdateEvent(false); this.Symbol = symbol; if (IsIndexSymbol(symbol)) this.Right = 0; //指数没有复权 if (this.Frame && this.Frame.SubFrame) //清空指标 { for (var i = 0; i < this.Frame.SubFrame.length; ++i) this.DeleteIndexPaint(i); } if (ChartData.IsDayPeriod(this.Period, true)) { this.RequestHistoryData(); //请求日线数据 //this.ReqeustKLineInfoData(); } else if (ChartData.IsMinutePeriod(this.Period, true) || ChartData.IsSecondPeriod(this.Period)) { this.ReqeustHistoryMinuteData(); //请求分钟数据 } } this.ReqeustKLineInfoData = function () { if (this.ChartPaint.length > 0) { var klinePaint = this.ChartPaint[0]; klinePaint.InfoData = new Map(); } //信息地雷信息 for (var i in this.ChartInfo) { this.ChartInfo[i].RequestData(this); } } //设置K线信息地雷 this.SetKLineInfo = function (aryInfo, bUpdate) { this.ChartInfo = []; //清空信息地雷 for (var i in aryInfo) { var infoItem = JSKLineInfoMap.Get(aryInfo[i]); if (!infoItem) continue; var item = infoItem.Create(); item.MaxReqeustDataCount = this.MaxReqeustDataCount; this.ChartInfo.push(item); } if (bUpdate == true) this.ReqeustKLineInfoData(); } this.SetPolicyInfo = function (aryPolicy, bUpdate) { if (!aryPolicy || !aryPolicy.length) return; var infoItem = JSKLineInfoMap.Get('策略选股'); if (!infoItem) return; var policyInfo = infoItem.Create(); policyInfo.SetPolicyList(aryPolicy); policyInfo.MaxReqeustDataCount = this.MaxReqeustDataCount; this.ChartInfo.push(policyInfo); if (bUpdate == true) this.ReqeustKLineInfoData(); } //叠加股票 this.OverlaySymbol = function (symbol,option) { var paint = this.OverlayChartPaint[0]; if (!paint.MainData) return false; paint.Symbol = symbol; if (option) { if (paint.Color) paint.Color = option.Color; } if (ChartData.IsDayPeriod(this.Period, true)) this.RequestOverlayHistoryData(); //请求日线数据 return true; } this.GetRequestDataCount = function () //K线请求数据个数 (由于可以拖拽下载历史数据,所有原来固定个数的就不能用了) { var result = { MaxRequestDataCount: this.MaxReqeustDataCount, MaxRequestMinuteDayCount: this.MaxRequestMinuteDayCount }; if (!this.SourceData || !this.SourceData.Data || this.SourceData.Data.length <= 0) return result; if (ChartData.IsDayPeriod(this.Period, true)) { var lCount = this.SourceData.Data.length; if (lCount > result.MaxRequestDataCount) result.MaxRequestDataCount = lCount; } else if (ChartData.IsMinutePeriod(this.Period, true)) { } return result; } this.RequestOverlayHistoryData = function () { if (!this.OverlayChartPaint.length) return; var symbol = this.OverlayChartPaint[0].Symbol; if (!symbol) return; var self = this; var dataCount = this.GetRequestDataCount(); var firstDate = this.SourceData.Data[0].Date; if (this.NetworkFilter) { var obj = { Name: 'KLineChartContainer::RequestOverlayHistoryData', //类名:: Explain: '叠加股票日K线数据', Request: { Url: self.KLineApiUrl, Data: { symbol: symbol, count: dataCount.MaxRequestDataCount, "first": { date: firstDate }, field: ["name", "symbol", "yclose", "open", "price", "high", 'vol', 'amount'] }, Type: 'POST' }, Self: this, PreventDefault: false }; this.NetworkFilter(obj, function (data) { self.RecvOverlayHistoryData(data); }); if (obj.PreventDefault == true) return; //已被上层替换,不调用默认的网络请求 } //请求数据 wx.request({ url: this.KLineApiUrl, data: { "field":["name","symbol","yclose","open","price","high"], "symbol": symbol, "start": -1, "count": this.MaxReqeustDataCount }, method: 'POST', dataType: "json", async: true, success: function (data) { self.RecvOverlayHistoryData(data); } }); } this.RecvOverlayHistoryData = function (recvData) { var data = recvData.data; var aryDayData = KLineChartContainer.JsonDataToHistoryData(data); //原始叠加数据 var sourceData = new ChartData(); sourceData.Data = aryDayData; var bindData = new ChartData(); bindData.Data = aryDayData; bindData.Period = this.Period; bindData.Right = this.Right; if (bindData.Right > 0 && !IsIndexSymbol(data.symbol)) //复权数据 ,指数没有复权) { var rightData = bindData.GetRightDate(bindData.Right); bindData.Data = rightData; } var aryOverlayData = this.SourceData.GetOverlayData(bindData.Data); //和主图数据拟合以后的数据 bindData.Data = aryOverlayData; if (ChartData.IsDayPeriod(bindData.Period, false)) //周期数据 { var periodData = bindData.GetPeriodData(bindData.Period); bindData.Data = periodData; } this.OverlayChartPaint[0].Data = bindData; this.OverlayChartPaint[0].SourceData = sourceData; this.OverlayChartPaint[0].Title = data.name; this.OverlayChartPaint[0].Symbol = data.symbol; this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType = 1; //调整为百份比坐标 this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } //取消叠加股票 this.ClearOverlaySymbol = function () { this.OverlayChartPaint[0].Symbol = null; this.OverlayChartPaint[0].Data = null; this.OverlayChartPaint[0].SourceData = null; this.OverlayChartPaint[0].TooltipRect = []; this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType = 0; //调整一般坐标 this.UpdateFrameMaxMin(); this.Draw(); } //创建画图工具 this.CreateChartDrawPicture = function (name) { return false; } this.SetChartDrawPictureFirstPoint = function (x, y) { var drawPicture = this.CurrentChartDrawPicture; if (!drawPicture) return false; if (!this.Frame.SubFrame || this.Frame.SubFrame.length <= 0) return false; for (var i in this.Frame.SubFrame) { var frame = this.Frame.SubFrame[i].Frame; var left = frame.ChartBorder.GetLeft(); var top = frame.ChartBorder.GetTopEx(); var height = frame.ChartBorder.GetHeight(); var width = frame.ChartBorder.GetWidth(); this.Canvas.rect(left, top, width, height); if (this.Canvas.isPointInPath(x, y)) { drawPicture.Frame = frame; break; } } if (!drawPicture.Frame) return false; drawPicture.Point[0] = new Point(); drawPicture.Point[0].X = x - this.UIElement.getBoundingClientRect().left; drawPicture.Point[0].Y = y - this.UIElement.getBoundingClientRect().top; drawPicture.Status = 1; //第1个点完成 } this.SetChartDrawPictureSecondPoint = function (x, y) { var drawPicture = this.CurrentChartDrawPicture; if (!drawPicture) return false; drawPicture.Point[1] = new Point(); drawPicture.Point[1].X = x - this.UIElement.getBoundingClientRect().left; drawPicture.Point[1].Y = y - this.UIElement.getBoundingClientRect().top; drawPicture.Status = 2; //设置第2个点 } //xStep,yStep 移动的偏移量 this.MoveChartDrawPicture = function (xStep, yStep) { var drawPicture = this.CurrentChartDrawPicture; if (!drawPicture) return false; //JSConsole.Chart.Log("xStep="+xStep+" yStep="+yStep); drawPicture.Move(xStep, yStep); return true; } this.FinishChartDrawPicturePoint = function () { var drawPicture = this.CurrentChartDrawPicture; if (!drawPicture) return false; if (drawPicture.PointCount != drawPicture.Point.length) return false; drawPicture.Status = 10; //完成 drawPicture.PointToValue(); this.ChartDrawPicture.push(drawPicture); this.CurrentChartDrawPicture = null; return true; } this.FinishMoveChartDrawPicture = function () { var drawPicture = this.CurrentChartDrawPicture; if (!drawPicture) return false; if (drawPicture.PointCount != drawPicture.Point.length) return false; drawPicture.Status = 10; //完成 drawPicture.PointToValue(); this.CurrentChartDrawPicture = null; return true; } //清空所有的画线工具 this.ClearChartDrawPicture = function (drawPicture) { if (!drawPicture) { this.ChartDrawPicture = []; this.Draw(); } else { for (var i in this.ChartDrawPicture) { if (this.ChartDrawPicture[i] == drawPicture) { this.ChartDrawPicture.splice(i, 1); this.Draw(); } } } } //更新信息地雷 this.UpdataChartInfo = function () { //TODO: 根据K线数据日期来做map, 不在K线上的合并到下一个k线日期里面 var mapInfoData = new Map(); if (this.Period==0) //日线数据 根据日期 { for (var i in this.ChartInfo) { var infoData = this.ChartInfo[i].Data; for (var j in infoData) { var item = infoData[j]; if (mapInfoData.has(item.Date.toString())) mapInfoData.get(item.Date.toString()).Data.push(item); else mapInfoData.set(item.Date.toString(), { Data: new Array(item) }); } } } else if (ChartData.IsDayPeriod(this.Period,false)) { mapInfoData=new Map(); var hisData=this.ChartPaint[0].Data; if (hisData && hisData.Data && hisData.Data.length>0) { var fristKItem=hisData.Data[0]; var aryInfo=[]; for(var i in this.ChartInfo) { var infoItem=this.ChartInfo[i]; for(var j in infoItem.Data) { var item=infoItem.Data[j]; if (item.Date>=fristKItem.Date) //在K线范围内的才显示 aryInfo.push(item); } } aryInfo.sort(function(a,b) { return a.Date-b.Date }); //排序 for(var i=0;i 0) //复权 { var rightData = bindData.GetRightDate(bindData.Right); bindData.Data = rightData; } if (ChartData.IsDayPeriod(bindData.Period, false) || ChartData.IsMinutePeriod(bindData.Period, false)) //周期数据 { var periodData = bindData.GetPeriodData(bindData.Period); bindData.Data = periodData; } } this.WindowIndex[index].BindData(this, index, bindData); this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } //修改参数指标 this.ChangeWindowIndexParam = function (index) { this.WindowIndex[index].Index[0].Param += 1; this.WindowIndex[index].Index[1].Param += 1; this.UpdateWindowIndex(index); } this.OnDoubleClick = function (x, y, e) { var tooltip = new TooltipData(); for (var i in this.ChartPaint) { var item = this.ChartPaint[i]; if (item.GetTooltipData(x, y, tooltip)) break; } if (!tooltip.Data) return; e.data = { Chart: this, Tooltip: tooltip }; } this.CancelAutoUpdate=function() //关闭停止更新 { if (typeof (this.AutoUpdateTimer) == 'number') { clearTimeout(this.AutoUpdateTimer); this.AutoUpdateTimer = undefined; } } //数据自动更新 this.AutoUpdate = function (waitTime) //waitTime 更新时间 { this.CancelAutoUpdate(); if (!this.IsAutoUpdate) return; if (!this.Symbol) return; if (this.IsDestroy) return; var self = this; var marketStatus = MARKET_SUFFIX_NAME.GetMarketStatus(this.Symbol); if (marketStatus == 0 || marketStatus == 3) return; //闭市,盘后 var frequency = this.AutoUpdateFrequency; if (marketStatus == 1) //盘前 { this.AutoUpdateTimer=setTimeout(function () { self.AutoUpdate(); }, frequency); } else if (marketStatus == 2) //盘中 { this.AutoUpdateTimer=setTimeout(function () { if (ChartData.IsDayPeriod(self.Period, true)) { self.RequestRealtimeData(); //更新最新行情 //self.ReqeustKLineInfoData(); } else if (ChartData.IsMinutePeriod(self.Period, true) || ChartData.IsSecondPeriod(self.Period)) { self.RequestMinuteRealtimeData(); //请求分钟数据 } }, frequency); } } this.GetMaxPageSize = function () { let width = this.Frame.ChartBorder.GetWidth(); let barWidth = (ZOOM_SEED[ZOOM_SEED.length - 1][0] + ZOOM_SEED[ZOOM_SEED.length - 1][1]); let pageSize = parseInt(width / barWidth) - 8; JSConsole.Chart.Log(`[KLineChartContainer::GetMaxPageSize] width=${width} barWidth=${barWidth} pageSize=${pageSize}`); return pageSize } //数据拖拽下载 this.DragDownloadData = function () { var data = null; if (!this.Frame.Data) data = this.Frame.Data; else data = this.Frame.SubFrame[0].Frame.Data; if (!data) return false; if (data.DataOffset > 0) return; if (ChartData.IsMinutePeriod(this.Period, true)) //下载分钟数据 { JSConsole.Chart.Log(`[KLineChartContainer.DragDownloadData] Minute:[Enable=${this.DragDownload.Minute.Enable}, IsEnd=${this.DragDownload.Minute.IsEnd}, Status=${this.DragDownload.Minute.Status}]`); if (!this.DragDownload.Minute.Enable) return; if (this.DragDownload.Minute.IsEnd) return; //全部下载完了 if (this.DragDownload.Minute.Status != 0) return; this.RequestDragMinuteData(); } else if (ChartData.IsDayPeriod(this.Period, true)) // 下载日线 { JSConsole.Chart.Log(`[KLineChartContainer.DragDownloadData] Day:[Enable=${this.DragDownload.Minute.Enable}, IsEnd=${this.DragDownload.Minute.IsEnd}, Status=${this.DragDownload.Minute.Status}]`); if (!this.DragDownload.Day.Enable) return; if (this.DragDownload.Day.IsEnd) return; //全部下载完了 if (this.DragDownload.Day.Status != 0) return; this.RequestDragDayData(); } } this.RequestDragMinuteData = function () { var self = this; this.AutoUpdateEvent(false, 'KLineChartContainer::RequestDragMinuteData'); //停止自动更新 this.CancelAutoUpdate(); var download = this.DragDownload.Minute; download.Status = 1; var firstItem = this.SourceData.Data[0]; //最新的一条数据 var postData = { "field": ["name", "symbol", "yclose", "open", "price", "high", "low", "vol"], "symbol": self.Symbol, "enddate": firstItem.Date, "endtime": firstItem.Time, "count": self.MaxRequestMinuteDayCount, "first": { date: firstItem.Date, time: firstItem.Time }, }; if (this.NetworkFilter) { var obj = { Name: 'KLineChartContainer::RequestDragMinuteData', //类名::函数 Explain: '拖拽1分钟K线数据下载', Request: { Url: this.DragMinuteKLineApiUrl, Type: 'POST', Data: postData, Period:this.Period }, DragDownload: download, Self: this, PreventDefault: false }; this.NetworkFilter(obj, function (data) { self.RecvDragMinuteData(data); download.Status = 0; self.AutoUpdateEvent(true, 'KLineChartContainer::RequestDragMinuteData'); //自动更新 self.AutoUpdate(); }); if (obj.PreventDefault == true) return; //已被上层替换,不调用默认的网络请求 } wx.request({ url: this.DragMinuteKLineApiUrl, data: postData, method: 'POST', dataType: "json", async: true, success: function (data) { self.RecvDragMinuteData(data); download.Status = 0; self.AutoUpdateEvent(true, 'KLineChartContainer::RequestDragMinuteData'); //自动更新 self.AutoUpdate(); } }); } this.RecvDragMinuteData = function (recvdata) { var data=recvdata.data; var aryDayData = KLineChartContainer.JsonDataToMinuteHistoryData(data); var lastDataCount = this.GetHistoryDataCount(); //保存下上一次的数据个数 for (var i in aryDayData) //数据往前插 { var item = aryDayData[i]; this.SourceData.Data.splice(i, 0, item); } var bindData = new ChartData(); bindData.Data = this.SourceData.Data; bindData.Period = this.Period; bindData.Right = this.Right; bindData.DataType = this.SourceData.DataType; bindData.Symbol = this.Symbol; if (!this.IsApiPeriod) { if (ChartData.IsDayPeriod(bindData.Period, false) || ChartData.IsMinutePeriod(bindData.Period, false)) //周期数据 (0= 日线,4=1分钟线 不需要处理) { var periodData = bindData.GetPeriodData(bindData.Period); bindData.Data = periodData; } } //绑定数据 this.UpdateMainData(bindData, lastDataCount); this.BindInstructionIndexData(bindData); //执行指示脚本 for (var i = 0; i < this.Frame.SubFrame.length; ++i) { this.BindIndexData(i, bindData); } //刷新画图 this.UpdataDataoffset(); //更新数据偏移 this.UpdatePointByCursorIndex(); //更新十字光标位子 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } this.RequestDragDayData = function () { var self = this; this.AutoUpdateEvent(false, 'KLineChartContainer::RequestDragDayData'); //停止自动更新 this.CancelAutoUpdate(); var download = this.DragDownload.Day; download.Status = 1; var firstItem = this.SourceData.Data[0]; //最新的一条数据 var postData = { "field": ["name", "symbol", "yclose", "open", "price", "high", "low", "vol"], "symbol": self.Symbol, "enddate": firstItem.Date, "count": self.MaxReqeustDataCount, "first": { date: firstItem.Date } }; if (this.NetworkFilter) { var obj = { Name: 'KLineChartContainer::RequestDragDayData', //类名::函数 Explain: '拖拽日K数据下载', Request: { Url: this.DragKLineApiUrl, Type: 'POST', Data: postData , Period:this.Period, Right:this.Right }, DragDownload: download, Self: this, PreventDefault: false }; this.NetworkFilter(obj, function (data) { self.RecvDragDayData(data); download.Status = 0; self.AutoUpdateEvent(true, 'KLineChartContainer::RequestDragDayData'); //自动更新 self.AutoUpdate(); }); if (obj.PreventDefault == true) return; //已被上层替换,不调用默认的网络请求 } wx.request({ url: this.DragKLineApiUrl, data: postData, method: 'POST', dataType: "json", async: true, success: function (data) { self.RecvDragDayData(data); download.Status = 0; self.AutoUpdateEvent(true, 'KLineChartContainer::RequestDragDayData'); //自动更新 self.AutoUpdate(); } }); } this.RecvDragDayData = function (recvdata) { var data = recvdata.data; var aryDayData = KLineChartContainer.JsonDataToHistoryData(data); if (!aryDayData || aryDayData.length<=0) { this.DragDownload.Day.IsEnd=true; //下完了 return; } var lastDataCount = this.GetHistoryDataCount(); //保存下上一次的数据个数 for (var i in aryDayData) //数据往前插 { var item = aryDayData[i]; this.SourceData.Data.splice(i, 0, item); } var bindData = new ChartData(); bindData.Data = this.SourceData.Data; bindData.Period = this.Period; bindData.Right = this.Right; bindData.DataType = this.SourceData.DataType; bindData.Symbol = this.Symbol; if (!this.IsApiPeriod) { if (ChartData.IsDayPeriod(bindData.Period, false) || ChartData.IsMinutePeriod(bindData.Period, false)) //周期数据 (0= 日线,4=1分钟线 不需要处理) { var periodData = bindData.GetPeriodData(bindData.Period); bindData.Data = periodData; } } //绑定数据 this.UpdateMainData(bindData, lastDataCount); this.BindInstructionIndexData(bindData); //执行指示脚本 for (var i = 0; i < this.Frame.SubFrame.length; ++i) { this.BindIndexData(i, bindData); } //刷新画图 this.UpdataDataoffset(); //更新数据偏移 this.UpdatePointByCursorIndex(); //更新十字光标位子 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } this.SetCustomVerical = function (windowId, data) { if (!this.Frame) return; if (windowId >= this.Frame.SubFrame.length) return; var item = this.Frame.SubFrame[windowId]; if (item.Frame) item.Frame.CustomVerticalInfo = data; } this.OnSize=function() { if (!this.Frame) return; if (!this.Frame.OnSize) return; var obj=this.Frame.OnSize(); this.Frame.SetSizeChage(true); if (obj.Changed) { this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); } this.Draw(); } } //API 返回数据 转化为array[] KLineChartContainer.JsonDataToHistoryData = function (data) { var list = data.data; var aryDayData = new Array(); if (!list) return aryDayData; var upperSymbol = null; if (data.symbol) upperSymbol = data.symbol.toUpperCase(); var isFutures = false; //是否是期货 isFutures = MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol); var date = 0, yclose = 1, open = 2, high = 3, low = 4, close = 5, vol = 6, amount = 7, position = 8; for (var i = 0; i < list.length; ++i) { var item = new HistoryData(); var jsData = list[i]; item.Date = jsData[date]; item.Open = jsData[open]; item.YClose = jsData[yclose]; item.Close = jsData[close]; item.High = jsData[high]; item.Low = jsData[low]; item.Vol = jsData[vol]; //原始单位股 item.Amount = jsData[amount]; if (IFrameSplitOperator.IsNumber(jsData[position])) item.Position = jsData[position];//期货持仓 if (!IFrameSplitOperator.IsNumber(item.Open)) continue; aryDayData.push(item); } return aryDayData; } KLineChartContainer.JsonDataToRealtimeData = function (data) { var symbol = data.stock[0].symbol; var upperSymbol = symbol.toUpperCase(); var isSHSZ = MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol); var item = new HistoryData(); item.Date = data.stock[0].date; item.Open = data.stock[0].open; item.YClose = data.stock[0].yclose; item.High = data.stock[0].high; item.Low = data.stock[0].low; item.Vol=data.stock[0].vol; //单位股 item.Amount = data.stock[0].amount; item.Close = data.stock[0].price; if (IFrameSplitOperator.IsNumber(data.stock[0].position)) item.Position = data.stock[0].position; //持仓量 return item; } KLineChartContainer.JsonDataToMinuteRealtimeData = function (data) { var symbol = data.stock[0].symbol; var upperSymbol = symbol.toUpperCase(); var isSHSZ = MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol); var isFutures = MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol); var aryMinuteData = new Array(); var preClose = data.stock[0].yclose; //前一个数据价格 var date = data.stock[0].date; if (isFutures && data.stock[0].yclearing) preClose = data.stock[0].yclearing; //期货使用昨结算价 for (var i in data.stock[0].minute) { var jsData = data.stock[0].minute[i]; var item = new HistoryData(); item.Close = jsData.price; item.Open = jsData.open; item.High = jsData.high; item.Low = jsData.low; item.Vol = jsData.vol; //单位股 item.Amount = jsData.amount; if (jsData.date > 0) item.Date = jsData.date; else item.Date = date; item.Time = jsData.time; item.YClose = preClose; if (IFrameSplitOperator.IsNumber(jsData.position)) item.Position = jsData.position; //持仓量 if (!IFrameSplitOperator.IsNumber(item.Close)) //当前没有价格 使用上一个价格填充 { item.Close = preClose; item.Open = item.High = item.Low = item.Close; } //价格是0的 都用空 if (!IFrameSplitOperator.IsNumber(item.Open)) item.Open = null; if (!IFrameSplitOperator.IsNumber(item.Close)) item.Close = null; if (!IFrameSplitOperator.IsNumber(item.High)) item.High = null; if (!IFrameSplitOperator.IsNumber(item.Low)) item.Low = null; //上次价格 if (IFrameSplitOperator.IsNumber(jsData.price)) preClose = jsData.price; aryMinuteData[i] = item; } return aryMinuteData; } //API 返回数据 转化为array[] KLineChartContainer.JsonDataToMinuteHistoryData = function (data) { var upperSymbol = null; if (data.symbol) upperSymbol = data.symbol.toUpperCase(); var isSHSZ = false; if (upperSymbol) isSHSZ = MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol); var isFutures = false; //是否是期货 if (upperSymbol) isFutures = MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol); var list = data.data; var aryDayData = new Array(); var date = 0, yclose = 1, open = 2, high = 3, low = 4, close = 5, vol = 6, amount = 7, time = 8, position = 9; for (var i = 0; i < list.length; ++i) { var item = new HistoryData(); var jsData=list[i]; item.Date = jsData[date]; item.Open = jsData[open]; item.YClose = jsData[yclose]; item.Close = jsData[close]; item.High = jsData[high]; item.Low = jsData[low]; item.Vol = jsData[vol]; //原始单位股 item.Amount = jsData[amount]; item.Time = jsData[time]; if (IFrameSplitOperator.IsNumber(jsData[position])) item.Position = jsData[position]; //期货持仓 aryDayData.push(item); } return aryDayData; } /////////////////////////////////////////////////////////////////////////////////////////// // 走势图 // function MinuteChartContainer(uielement) { this.newMethod = JSChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.ClassName = 'MinuteChartContainer'; this.WindowIndex = new Array(); this.Symbol; this.Name; this.SourceData; //原始的历史数据 this.OverlaySourceData; //叠加的原始数据 this.IsAutoUpdate = false; //是否自动更新行情数据 this.AutoUpdateFrequency = 30000; //30秒更新一次数据 this.AutoUpdateTimer; //更新定时器 this.TradeDate = 0; //行情交易日期 this.LoadDataSplashTitle = '下载分钟数据'; this.UpdateUICallback; //数据到达回调 this.DayCount = 1; //显示几天的数据 this.DayData; //多日分钟数据 this.MinuteApiUrl = g_JSChartResource.Domain + "/API/Stock"; this.HistoryMinuteApiUrl = g_JSChartResource.Domain + "/API/StockMinuteData"; //历史分钟数据 //手机拖拽 this.ontouchstart = function (e) { if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return; this.IsOnTouch = true; var jsChart = this; if (jsChart.DragMode == 0) return; if (this.IsPhoneDragging(e)) { if (jsChart.TryClickLock) { var touches = this.GetToucheData(e, jsChart.IsForceLandscape); var x = touches[0].clientX; var y = touches[0].clientY; if (jsChart.TryClickLock(x, y)) return; } //长按2秒,十字光标 this.ClearTouchTimer(); var drag = { "Click": {}, "LastMove": {}, //最后移动的位置 }; var touches = this.GetToucheData(e, jsChart.IsForceLandscape); drag.Click.X = touches[0].clientX; drag.Click.Y = touches[0].clientY; drag.LastMove.X = touches[0].clientX; drag.LastMove.Y = touches[0].clientY; var T_ShowCorssCursor=()=> { if (this.ChartCorssCursor.IsShow === true) //移动十字光标 { var x = drag.Click.X; var y = drag.Click.Y; if (jsChart.IsForceLandscape) y = jsChart.UIElement.Height - drag.Click.Y; //强制横屏Y计算 jsChart.OnMouseMove(x, y, e); } } if (this.EnableZoomIndexWindow) { this.PhoneDBClick.AddTouchStart(touches[0].clientX, touches[0].clientY, Date.now()); JSConsole.Chart.Log("[MinuteChartContainer::OnTouchStart] PhoneDBClick ", this.PhoneDBClick); } if (this.EnableScrollUpDown==true) { this.TouchTimer=setTimeout(()=> { this.MouseDrag=null; T_ShowCorssCursor(); }, 800); } this.MouseDrag=drag; if (this.EnableScrollUpDown==false) T_ShowCorssCursor(); } } this.ontouchmove = function (e) { if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return; var jsChart = this; var drag = jsChart.MouseDrag; var touches = this.GetToucheData(e, jsChart.IsForceLandscape); if (this.ChartCorssCursor.IsShow === true && this.IsPhoneDragging(e)) { if (drag == null) { var x = touches[0].clientX; var y = touches[0].clientY; this.LastMovePoint={ X:x, Y:y }; if (this.DrawMoveTimer) return; this.DrawMoveTimer=setTimeout(()=> { if (!this.LastMovePoint) return; this.OnMouseMove(this.LastMovePoint.X, this.LastMovePoint.Y, e); this.DrawMoveTimer=null; }, this.DrawMoveWaitTime); } } if (drag!=null) { //TODO:上下滚动 this.ClearTouchTimer(); this.MouseDrag=null; var x = touches[0].clientX; var y = touches[0].clientY; this.OnMouseMove(x,y,e); } } //创建 //windowCount 窗口个数 this.Create = function (windowCount) { this.UIElement.JSChartContainer = this; //创建十字光标 this.ChartCorssCursor = new ChartCorssCursor(); this.ChartCorssCursor.Canvas = this.Canvas; this.ChartCorssCursor.StringFormatX = new HQMinuteTimeStringFormat(); this.ChartCorssCursor.StringFormatY = new HQPriceStringFormat(); this.ChartCorssCursor.StringFormatY.LanguageID = this.LanguageID; //创建等待提示 this.ChartSplashPaint = new ChartSplashPaint(); this.ChartSplashPaint.Canvas = this.Canvas; this.ChartSplashPaint.SplashTitle = this.LoadDataSplashTitle; this.ChartSplashPaint.HQChart=this; //创建框架容器 this.Frame = new HQTradeFrame(); this.Frame.ChartBorder = new ChartBorder(); this.Frame.ChartBorder.UIElement = this.UIElement; this.Frame.ChartBorder.Top = 25; this.Frame.ChartBorder.Left = 50; this.Frame.ChartBorder.Bottom = 20; this.Frame.Canvas = this.Canvas; this.Frame.ZoomStartWindowIndex=2; this.ChartCorssCursor.Frame = this.Frame; //十字光标绑定框架 this.ChartSplashPaint.Frame = this.Frame; this.CreateChildWindow(windowCount); this.CreateMainKLine(); //子窗口动态标题 for (var i in this.Frame.SubFrame) { var titlePaint = new DynamicChartTitlePainting(); titlePaint.Frame = this.Frame.SubFrame[i].Frame; titlePaint.Canvas = this.Canvas; titlePaint.LanguageID = this.LanguageID; this.TitlePaint.push(titlePaint); } this.ChartCorssCursor.StringFormatX.Frame = this.Frame.SubFrame[0].Frame; } //创建子窗口 this.CreateChildWindow = function (windowCount) { for (var i = 0; i < windowCount; ++i) { var border = new ChartBorder(); border.UIElement = this.UIElement; var frame = new MinuteFrame(); frame.Canvas = this.Canvas; frame.ChartBorder = border; frame.Identify=i; if (i < 2) frame.ChartBorder.TitleHeight = 0; frame.XPointCount = 243; var DEFAULT_HORIZONTAL = [9, 8, 7, 6, 5, 4, 3, 2, 1]; frame.HorizontalMax = DEFAULT_HORIZONTAL[0]; frame.HorizontalMin = DEFAULT_HORIZONTAL[DEFAULT_HORIZONTAL.length - 1]; if (i == 0) { frame.YSplitOperator = new FrameSplitMinutePriceY(); frame.YSplitOperator.FrameSplitData = this.FrameSplitData.get('price'); frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); } } else { frame.YSplitOperator = new FrameSplitY(); frame.YSplitOperator.FrameSplitData = this.FrameSplitData.get('double'); frame.YSplitOperator.LanguageID = this.LanguageID; frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); } } frame.YSplitOperator.Frame = frame; frame.YSplitOperator.ChartBorder = border; frame.XSplitOperator = new FrameSplitMinuteX(); frame.XSplitOperator.Frame = frame; frame.XSplitOperator.ChartBorder = border; if (i != windowCount - 1) frame.XSplitOperator.ShowText = false; frame.XSplitOperator.Operator(); for (var j in DEFAULT_HORIZONTAL) { frame.HorizontalInfo[j] = new CoordinateInfo(); frame.HorizontalInfo[j].Value = DEFAULT_HORIZONTAL[j]; if (i == 0 && j == frame.HorizontalMin) continue; frame.HorizontalInfo[j].Message[1] = DEFAULT_HORIZONTAL[j].toString(); frame.HorizontalInfo[j].Font = "14px 微软雅黑"; } var subFrame = new SubFrameItem(); subFrame.Frame = frame; if (i == 0) subFrame.Height = 20; else subFrame.Height = 10; this.Frame.SubFrame[i] = subFrame; } } this.CreateSubFrameItem=function(id) { var border=new ChartBorder(); border.UIElement=this.UIElement; var frame=new MinuteFrame(); frame.Canvas=this.Canvas; frame.ChartBorder=border; frame.Identify=id; //窗口序号 frame.XPointCount=243; if (id>=2) { if (this.ModifyIndexDialog) frame.ModifyIndexEvent=this.ModifyIndexDialog.DoModal; //绑定菜单事件 if (this.ChangeIndexDialog) frame.ChangeIndexEvent=this.ChangeIndexDialog.DoModal; } var DEFAULT_HORIZONTAL=[9,8,7,6,5,4,3,2,1]; frame.HorizontalMax=DEFAULT_HORIZONTAL[0]; frame.HorizontalMin=DEFAULT_HORIZONTAL[DEFAULT_HORIZONTAL.length-1]; frame.YSplitOperator=new FrameSplitY(); frame.YSplitOperator.LanguageID=this.LanguageID; frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double'); frame.YSplitOperator.Frame=frame; frame.YSplitOperator.ChartBorder=border; frame.XSplitOperator=new FrameSplitMinuteX(); frame.XSplitOperator.Frame=frame; frame.XSplitOperator.ChartBorder=border; frame.XSplitOperator.ShowText=false; frame.XSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); } frame.YSplitOperator.GetEventCallback=(id)=> { return this.GetEventCallback(id); } //K线数据绑定 var xPointCouont=this.Frame.SubFrame[0].Frame.XPointCount; frame.XPointCount=xPointCouont; frame.Data=this.ChartPaint[0].Data; for(var j in DEFAULT_HORIZONTAL) { frame.HorizontalInfo[j]= new CoordinateInfo(); frame.HorizontalInfo[j].Value=DEFAULT_HORIZONTAL[j]; frame.HorizontalInfo[j].Message[1]=DEFAULT_HORIZONTAL[j].toString(); frame.HorizontalInfo[j].Font="14px 微软雅黑"; } var subFrame=new SubFrameItem(); subFrame.Frame=frame; subFrame.Height=10; return subFrame; } this.UpdateXShowText=function() { var bLastFrame=true; for(var i=this.Frame.SubFrame.length-1;i>=0;--i) { var item=this.Frame.SubFrame[i].Frame; var subFrame=this.Frame.SubFrame[i]; if (bLastFrame) { item.XSplitOperator.ShowText=true; if (subFrame.Height>0) bLastFrame=false; } else { item.XSplitOperator.ShowText=false; } } } //删除某一个窗口的指标 this.DeleteIndexPaint = function (windowIndex) { let paint = new Array(); for (let i in this.ChartPaint) //踢出当前窗口的指标画法 { let item = this.ChartPaint[i]; if (i == 0 || item.ChartFrame != this.Frame.SubFrame[windowIndex].Frame) paint.push(item); } //清空指定最大最小值 this.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin = null; this.Frame.SubFrame[windowIndex].Frame.IsLocked = false; //解除上锁 this.ChartPaint = paint; //清空东条标题 var titleIndex = windowIndex + 1; this.TitlePaint[titleIndex].Data = []; this.TitlePaint[titleIndex].Title = null; } this.CreateStockInfo = function () { this.ExtendChartPaint[0] = new StockInfoExtendChartPaint(); this.ExtendChartPaint[0].Canvas = this.Canvas; this.ExtendChartPaint[0].ChartBorder = this.Frame.ChartBorder; this.ExtendChartPaint[0].ChartFrame = this.Frame; this.Frame.ChartBorder.Right = 300; } //创建主图K线画法 this.CreateMainKLine = function () { //分钟线 var minuteLine = new ChartMinutePriceLine(); minuteLine.Canvas = this.Canvas; minuteLine.ChartBorder = this.Frame.SubFrame[0].Frame.ChartBorder; minuteLine.ChartFrame = this.Frame.SubFrame[0].Frame; minuteLine.Name = "Minute-Line"; minuteLine.Color = g_JSChartResource.Minute.PriceColor; minuteLine.AreaColor = g_JSChartResource.Minute.AreaPriceColor; this.ChartPaint[0] = minuteLine; //分钟线均线 var averageLine = new ChartMinutePriceLine(); averageLine.Canvas = this.Canvas; averageLine.ChartBorder = this.Frame.SubFrame[0].Frame.ChartBorder; averageLine.ChartFrame = this.Frame.SubFrame[0].Frame; averageLine.Name = "Minute-Average-Line"; averageLine.Color = g_JSChartResource.Minute.AvPriceColor; averageLine.IsDrawArea = false; this.ChartPaint[1] = averageLine; //成交量柱子 var chartVol = new ChartMinuteVolumBar(); chartVol.Color = g_JSChartResource.Minute.VolBarColor; chartVol.Canvas = this.Canvas; chartVol.ChartBorder = this.Frame.SubFrame[1].Frame.ChartBorder; chartVol.ChartFrame = this.Frame.SubFrame[1].Frame; chartVol.Name = "Minute-Vol-Bar"; this.ChartPaint[2] = chartVol; //持仓线 var chartPosition=new ChartSubLine(); chartPosition.Color = g_JSChartResource.Minute.PriceColor; chartPosition.Canvas = this.Canvas; chartPosition.ChartBorder = this.Frame.SubFrame[1].Frame.ChartBorder; chartPosition.ChartFrame = this.Frame.SubFrame[1].Frame; chartPosition.Name = "Minute-Position-Line"; this.ChartPaint[3] = chartPosition; this.TitlePaint[0] = new DynamicMinuteTitlePainting(); this.TitlePaint[0].Frame = this.Frame.SubFrame[0].Frame; this.TitlePaint[0].Canvas = this.Canvas; this.TitlePaint[0].LanguageID = this.LanguageID; //主图叠加画法 var paint = new ChartOverlayMinutePriceLine(); paint.Canvas = this.Canvas; paint.ChartBorder = this.Frame.SubFrame[0].Frame.ChartBorder; paint.ChartFrame = this.Frame.SubFrame[0].Frame; paint.Name = "Overlay-Minute"; this.OverlayChartPaint[0] = paint; } //切换成 脚本指标 this.ChangeScriptIndex = function (windowIndex, indexData) { this.DeleteIndexPaint(windowIndex); this.WindowIndex[windowIndex] = new ScriptIndex(indexData.Name, indexData.Script, indexData.Args, indexData); //脚本执行 var bindData = this.SourceData; this.BindIndexData(windowIndex, bindData); //执行脚本 this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } this.ChangeIndex = function (windowIndex, indexName, option) { if (this.Frame.SubFrame.length < 3) return; //查找系统指标 let scriptData = new JSCommonIndexScript.JSIndexScript(); let indexInfo = scriptData.Get(indexName); if (!indexInfo) return; if (windowIndex < 2) windowIndex = 2; if (windowIndex >= this.Frame.SubFrame.length) windowIndex = 2; let indexData = { Name: indexInfo.Name, Script: indexInfo.Script, Args: indexInfo.Args, ID: indexName, //扩展属性 可以是空 KLineType: indexInfo.KLineType, YSpecificMaxMin: indexInfo.YSpecificMaxMin, YSplitScale: indexInfo.YSplitScale, FloatPrecision: indexInfo.FloatPrecision, Condition: indexInfo.Condition, StringFormat: indexInfo.StringFormat }; if (option) { if (option.FloatPrecision >= 0) indexData.FloatPrecision = option.FloatPrecision; if (option.StringFormat > 0) indexData.StringFormat = option.StringFormat; if (option.Args) indexData.Args = option.Args; } return this.ChangeScriptIndex(windowIndex, indexData); } this.RemoveIndexWindow=function(id) { JSConsole.Chart.Log('[MinuteChartContainer::RemoveIndexWindow] remove id', id); if (id<2) return; if (!this.Frame.SubFrame) return; if (id>=this.Frame.SubFrame.length) return; var delFrame=this.Frame.SubFrame[id].Frame; this.DeleteIndexPaint(id); this.Frame.SubFrame.splice(id,1); this.WindowIndex.splice(id,1); this.TitlePaint.splice(id+1,1); //删除对应的动态标题 for(var i=0;i 10) return; this.DayCount = count; this.CancelAutoUpdate(); //先停止定时器 this.RequestData(); } //叠加股票 只支持日线数据 this.OverlaySymbol = function (symbol,option) { var paint = this.OverlayChartPaint[0]; if (!paint.MainData) return false; paint.Symbol = symbol; if (option) { if (option.Color) paint.Color=option.Color; } if (this.DayCount <= 1) this.RequestOverlayMinuteData(); //请求数据 else this.RequestOverlayHistoryMinuteData(); return true; } this.TryClickLock = function (x, y) { for (let i in this.Frame.SubFrame) { var item = this.Frame.SubFrame[i]; if (!item.Frame.IsLocked) continue; if (!item.Frame.LockPaint) continue; var tooltip = new TooltipData(); if (!item.Frame.LockPaint.GetTooltipData(x, y, tooltip)) continue; tooltip.HQChart = this; if (tooltip.Data.Callback) tooltip.Data.Callback(tooltip); return true; } return false; } this.RequestData = function () { if (this.DayCount <= 1) this.RequestMinuteData(); else this.RequestHistoryMinuteData(); //请求数据 } this.RecvMinuteDataEvent = function () { if (!this.mapEvent.has(JSCHART_EVENT_ID.RECV_MINUTE_DATA)) return; var event = this.mapEvent.get(JSCHART_EVENT_ID.RECV_MINUTE_DATA); var data = { MinuteData: this.SourceData, Stock: { Symbol: this.Symbol, Name: this.Name } } event.Callback(event, data, this); } this.RequestHistoryMinuteData = function () //请求历史分钟数据 { var self = this; this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle); this.ChartSplashPaint.EnableSplash(true); this.Draw(); if (this.NetworkFilter) { var obj = { Name: 'MinuteChartContainer::RequestHistoryMinuteData', //类名:: Explain: '多日分时数据', Request: { Url: self.HistoryMinuteApiUrl, Data: { daycount: self.DayCount, symbol: self.Symbol }, Type: 'POST' }, Self: this, PreventDefault: false }; this.NetworkFilter(obj, function (data) { self.ChartSplashPaint.EnableSplash(false); self.RecvHistoryMinuteData(data); }); if (obj.PreventDefault == true) return; //已被上层替换,不调用默认的网络请求 } wx.request({ url: self.HistoryMinuteApiUrl, data: { "symbol": self.Symbol, "daycount": self.DayCount }, method: "post", dataType: "json", success: function (data) { self.ChartSplashPaint.EnableSplash(false); self.RecvHistoryMinuteData(data); } }); } this.RecvHistoryMinuteData = function (recvdata) { var data = recvdata.data; if (data.code!=0) { JSConsole.Chart.Log('[MinuteChartContainer::RecvHistoryMinuteData] failed.',data); return; } this.DayData = MinuteChartContainer.JsonDataToMinuteDataArray(data);; this.Symbol = data.symbol; this.Name = data.name; this.CaclutateLimitPrice(this.DayData[0].YClose, data.data[0].limitprice); //计算涨停价格 this.UpdateHistoryMinuteUI(); this.RecvMinuteDataEvent(); this.RequestOverlayHistoryMinuteData(); if (typeof (this.UpdateUICallback) == 'function') this.UpdateUICallback('RecvHistoryMinuteData', this); this.AutoUpdate(); } this.CaclutateLimitPrice=function(yClose, limitData) { this.LimitPrice=null; //var limitData=data.stock[0].limitprice; if (limitData && limitData.max>0 && limitData.min>0) //API里带涨停价格 直接使用 { this.LimitPrice={ Max:limitData.max, Min:limitData.min }; return; } var range=MARKET_SUFFIX_NAME.GetLimitPriceRange(this.Symbol, this.Name); //通过规则获取涨停价格 if (!range) { JSConsole.Chart.Log(`[MinuteChartContainer::CaclutateLimitPrice] ${this.Symbol} no limit price.`) return; } //var yClose=data.stock[0].yclose; if (yClose<=0) return; this.LimitPrice={ Max:yClose*(1+range.Max), Min:yClose*(1+range.Min) }; JSConsole.Chart.Log(`[MinuteChartContainer::CaclutateLimitPrice] ${this.Symbol} yClose:${yClose} max:${this.LimitPrice.Max} min:${this.LimitPrice.Min}`); this.LimitPrice.Max=parseFloat(this.LimitPrice.Max.toFixed(2)); this.LimitPrice.Min=parseFloat(this.LimitPrice.Min.toFixed(2)); JSConsole.Chart.Log(`[MinuteChartContainer::CaclutateLimitPrice] ${this.Symbol} tofixed(2) max:${this.LimitPrice.Max} min:${this.LimitPrice.Min}`); } this.UpdateHistoryMinuteUI = function () { var allMinuteData = this.HistoryMinuteDataToArray(this.DayData); //原始数据 var sourceData = new ChartData(); sourceData.Data = allMinuteData; this.SourceData = sourceData; this.TradeDate = this.DayData[0].Date; this.BindMainData(sourceData, this.DayData[0].YClose); //if (MARKET_SUFFIX_NAME.IsChinaFutures(this.Symbol)) this.ChartPaint[1].Data = null; //期货均线暂时不用 if (this.Frame.SubFrame.length > 2) { var bindData = new ChartData(); bindData.Data = allMinuteData; for (var i = 2; i < this.Frame.SubFrame.length; ++i) { this.BindIndexData(i, bindData); } } for (let i in this.Frame.SubFrame) { var item = this.Frame.SubFrame[i]; item.Frame.XSplitOperator.Symbol = this.Symbol; item.Frame.XSplitOperator.DayCount = this.DayData.length; item.Frame.XSplitOperator.DayData = this.DayData; item.Frame.XSplitOperator.Operator(); //调整X轴个数 item.Frame.YSplitOperator.Symbol = this.Symbol; } this.ChartCorssCursor.StringFormatY.Symbol = this.Symbol; this.ChartCorssCursor.StringFormatX.Symbol = this.Symbol; this.TitlePaint[0].IsShowDate = true; this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } this.HistoryMinuteDataToArray = function (data) //把多日分钟数据转化为单数组 { var result = []; for (var i = data.length - 1; i >= 0; --i) { var item = data[i]; for (var j in item.Data) { result.push(item.Data[j]); } } return result; } this.UpdateLatestMinuteData = function (data, date) //更新最新交易日的分钟数据 { for (var i in this.DayData) { var item = this.DayData[i]; if (item.Date === date) { item.Data = data; break; } } } //请求分钟数据 this.RequestMinuteData = function () { var self = this; var fields = [ "name", "symbol", "yclose", "open", "price", "high", "low", "vol", "amount", "date", "time", "minute", "minutecount" ]; var upperSymbol = this.Symbol.toUpperCase(); if (MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol)) //期货的需要加上结算价 { fields.push("clearing"); fields.push("yclearing"); } if (this.NetworkFilter) { var obj = { Name: 'MinuteChartContainer::RequestMinuteData', //类名::函数名 Explain: '最新分时数据', Request: { Url: self.MinuteApiUrl, Data: { field: fields, symbol: [self.Symbol] }, Type: 'POST' }, Self: this, PreventDefault: false }; this.NetworkFilter(obj, function (data) { self.ChartSplashPaint.EnableSplash(false); self.RecvMinuteData(data); }); if (obj.PreventDefault == true) return; //已被上层替换,不调用默认的网络请求 } wx.request({ url: this.MinuteApiUrl, data: { "field": fields, "symbol": [this.Symbol], "start": -1 }, method: "post", dataType: "json", success: function (data) { self.ChartSplashPaint.EnableSplash(false); self.RecvMinuteData(data); } }); } this.RecvMinuteData = function (data) { var aryMinuteData = MinuteChartContainer.JsonDataToMinuteData(data.data); if (this.DayCount > 1) //多日走势图 { this.UpdateLatestMinuteData(aryMinuteData, data.data.stock[0].date); this.UpdateHistoryMinuteUI(); this.RecvMinuteDataEvent(); this.RequestOverlayMinuteData(); //更新最新叠加数据 if (typeof (this.UpdateUICallback) == 'function') this.UpdateUICallback('RecvMinuteData', this); this.AutoUpdate(); return; } //原始数据 var sourceData = new ChartData(); sourceData.Data = aryMinuteData; this.TradeDate = data.data.stock[0].date; this.SourceData = sourceData; this.Symbol = data.data.stock[0].symbol; this.Name = data.data.stock[0].name; var yClose = data.data.stock[0].yclose; var upperSymbol = this.Symbol.toUpperCase(); var isFutures = MARKET_SUFFIX_NAME.IsFutures(upperSymbol); if (data.data.stock[0].yclearing && isFutures) yClose = data.data.stock[0].yclearing; //期货使用前结算价 this.CaclutateLimitPrice(yClose, data.data.stock[0].limitprice); //计算涨停价格 var extendData = { High: data.data.stock[0].high, Low: data.data.stock[0].low }; this.BindMainData(sourceData, yClose, extendData); for (let i in this.Frame.SubFrame) //把股票代码设置到X轴刻度类里 { var item = this.Frame.SubFrame[i]; item.Frame.XSplitOperator.Symbol = this.Symbol; item.Frame.XSplitOperator.DayCount = 1; item.Frame.XSplitOperator.Operator(); //调整X轴个数 item.Frame.YSplitOperator.Symbol = this.Symbol; } //计算指标 if (this.Frame.SubFrame.length > 2) { var bindData = new ChartData(); bindData.Data = aryMinuteData; for (var i = 2; i < this.Frame.SubFrame.length; ++i) { this.BindIndexData(i, bindData); } } this.ChartCorssCursor.StringFormatY.Symbol = this.Symbol; this.ChartCorssCursor.StringFormatX.Symbol = this.Symbol; var chartInfo = this.GetChartMinuteInfo(); if (chartInfo) chartInfo.SourceData = this.SourceData; //数据绑定到信息地雷上 this.RecvMinuteDataEvent(); this.RequestMinuteInfoData(); this.RequestOverlayMinuteData();//请求叠加数据 (主数据下载完再下载) this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); if (typeof (this.UpdateUICallback) == 'function') this.UpdateUICallback('RecvMinuteData', this); this.AutoUpdate(); } //请求叠加数据 (主数据下载完再下载)) this.RequestOverlayMinuteData = function () { if (!this.OverlayChartPaint.length) return; var symbol = this.OverlayChartPaint[0].Symbol; if (!symbol) return; var self = this; var date = this.TradeDate; //最后一个交易日期 if (this.NetworkFilter) { var obj = { Name: 'MinuteChartContainer::RequestOverlayMinuteData', //类名::函数名 Explain: '叠加股票最新分时数据', Request: { Url: self.HistoryMinuteApiUrl, Data: { days: [date], symbol: symbol }, Type: 'POST' }, Self: this, PreventDefault: false }; this.NetworkFilter(obj, function (data) { self.RecvOverlayMinuteData(data); }); if (obj.PreventDefault == true) return; //已被上层替换,不调用默认的网络请求 } //请求数据 wx.request({ url: self.HistoryMinuteApiUrl, data: { "symbol": symbol, "days": [date], }, method: "post", dataType: "json", success: function (data) { self.RecvOverlayMinuteData(data); } }); } this.RecvOverlayMinuteData = function (recvData) { var data = recvData.data; var aryMinuteData = MinuteChartContainer.JsonDataToMinuteDataArray(data); var sourceData = null; var yClose; if (this.DayCount > 1) //多日数据 { if (aryMinuteData.length <= 0) return; var minuteData = aryMinuteData[0]; for (var i in this.OverlaySourceData) { var item = this.OverlaySourceData[i]; if (item.Date == minuteData.Date) { this.OverlaySourceData[i] = minuteData; var allMinuteData = this.HistoryMinuteDataToArray(this.OverlaySourceData); var sourceData = new ChartData(); sourceData.Data = allMinuteData; yClose = minuteData.YClose; break; } } if (sourceData == null) return; } else { if (aryMinuteData.length > 0) sourceData = aryMinuteData[0]; else sourceData = new ChartData(); yClose = sourceData.YClose; } this.OverlayChartPaint[0].Data = sourceData; this.OverlayChartPaint[0].Title = data.name; this.OverlayChartPaint[0].Symbol = data.symbol; this.OverlayChartPaint[0].YClose = yClose; this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); if (typeof (this.UpdateUICallback) == 'function') this.UpdateUICallback('RecvOverlayMinuteData', this); } this.RequestOverlayHistoryMinuteData = function () { if (!this.OverlayChartPaint.length) return; var symbol = this.OverlayChartPaint[0].Symbol; if (!symbol) return; var self = this; var days = []; for (var i in this.DayData) { var item = this.DayData[i]; days.push(item.Date); } if (days.length <= 0) return; if (this.NetworkFilter) { var obj = { Name: 'MinuteChartContainer::RequestOverlayHistoryMinuteData', //类名::函数名 Explain: '叠加股票多日分时数据', Request: { Url: self.HistoryMinuteApiUrl, Data: { days: days, symbol: symbol }, Type: 'POST' }, Self: this, PreventDefault: false }; this.NetworkFilter(obj, function (data) { self.RecvOverlayHistoryMinuteData(data); }); if (obj.PreventDefault == true) return; //已被上层替换,不调用默认的网络请求 } wx.request({ url: self.HistoryMinuteApiUrl, data: { "symbol": symbol, "days": days }, method: "post", dataType: "json", async: true, success: function (data) { self.RecvOverlayHistoryMinuteData(data); } }); } this.RecvOverlayHistoryMinuteData = function (recvData) //叠加历史的分钟数据 { var data = recvData.data; var dayData = MinuteChartContainer.JsonDataToMinuteDataArray(data); var overlayDayData = []; for (var i in this.DayData) { var item = this.DayData[i]; var bFind = false; for (var j in dayData) { if (item.Date == dayData[j].Date) { overlayDayData.push(dayData[i]); bFind = true; break; } } if (!bFind) //当天不存在叠加数据, 存空 { var empytData = new ChartData(); empytData.Date = item.Date; } } this.OverlaySourceData = overlayDayData; var allMinuteData = this.HistoryMinuteDataToArray(overlayDayData); //原始数据 var sourceData = new ChartData(); sourceData.Data = allMinuteData; var yClose = overlayDayData[0].YClose; this.OverlayChartPaint[0].Data = sourceData; this.OverlayChartPaint[0].Title = data.name; this.OverlayChartPaint[0].Symbol = data.symbol; this.OverlayChartPaint[0].YClose = yClose; this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); if (typeof (this.UpdateUICallback) == 'function') this.UpdateUICallback('RecvOverlayHistoryMinuteData', this); } this.CancelAutoUpdate = function () //关闭停止更新 { if (typeof (this.AutoUpdateTimer) == 'number') { clearTimeout(this.AutoUpdateTimer); this.AutoUpdateTimer = undefined; } } //数据自动更新 this.AutoUpdate = function () { this.CancelAutoUpdate(); if (!this.IsAutoUpdate) return; if (!this.Symbol) return; if (this.IsDestroy) return; var self = this; var marketStatus = MARKET_SUFFIX_NAME.GetMarketStatus(this.Symbol); if (marketStatus == 0 || marketStatus == 3) return; //闭市,盘后 var frequency = this.AutoUpdateFrequency; if (marketStatus == 1) //盘前 { this.AutoUpdateTimer=setTimeout(function () { self.AutoUpdate(); }, frequency); } else if (marketStatus == 2) //盘中 { this.AutoUpdateTimer=setTimeout(function () { //self.ResetOverlaySymbolStatus(); self.RequestMinuteData(); }, frequency); } } this.StopAutoUpdate = function () { this.CancelAutoUpdate(); this.IsAutoUpdate = false; } this.BindIndexData = function (windowIndex, hisData) { if (!this.WindowIndex[windowIndex]) return; if (typeof (this.WindowIndex[windowIndex].RequestData) == "function") //数据需要另外下载的. { this.WindowIndex[windowIndex].RequestData(this, windowIndex, hisData); return; } if (typeof (this.WindowIndex[windowIndex].ExecuteScript) == 'function') { this.WindowIndex[windowIndex].ExecuteScript(this, windowIndex, hisData); return; } this.WindowIndex[windowIndex].BindData(this, windowIndex, hisData); } this.BindMainData = function (minuteData, yClose, extendData) //绑定分钟数据 { //分钟数据 var bindData = new ChartData(); bindData.Data = minuteData.GetClose(); this.ChartPaint[0].Data = bindData; this.ChartPaint[0].YClose = yClose; this.ChartPaint[0].NotSupportMessage = null; this.Frame.SubFrame[0].Frame.YSplitOperator.YClose = yClose; this.Frame.SubFrame[0].Frame.YSplitOperator.Data = bindData; //均线 bindData = new ChartData(); bindData.Data = minuteData.GetMinuteAvPrice(); this.ChartPaint[1].Data = bindData; this.Frame.SubFrame[0].Frame.YSplitOperator.AverageData = bindData; this.Frame.SubFrame[0].Frame.YSplitOperator.OverlayChartPaint = this.OverlayChartPaint; this.Frame.SubFrame[0].Frame.YSplitOperator.LimitPrice=this.LimitPrice; if (extendData) { this.Frame.SubFrame[0].Frame.YSplitOperator.High = extendData.High; this.Frame.SubFrame[0].Frame.YSplitOperator.Low = extendData.Low; } //成交量 this.ChartPaint[2].Data = minuteData; this.ChartPaint[2].YClose = yClose; var upperSymbol=this.Symbol.toUpperCase(); var bFutures=MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol); var bSHO = MARKET_SUFFIX_NAME.IsSHO(upperSymbol); if (bFutures || bSHO) { this.ChartPaint[3].Data.Data = minuteData.GetPosition(); } else { this.ChartPaint[3].Data.Data=null; } this.TitlePaint[0].Data = this.SourceData; //动态标题 this.TitlePaint[0].Symbol = this.Symbol; this.TitlePaint[0].Name = this.Name; this.TitlePaint[0].YClose = yClose; if (this.ChartCorssCursor) { if (this.ChartCorssCursor.StringFormatY) { this.ChartCorssCursor.StringFormatY.YClose=yClose; this.ChartCorssCursor.StringFormatX.Data=this.ChartPaint[0].Data; //十字光标 } } if (this.ExtendChartPaint[0]) { this.ExtendChartPaint[0].Symbol = this.Symbol; this.ExtendChartPaint[0].Name = this.Name; } this.OverlayChartPaint[0].MainData = this.ChartPaint[0].Data; //叠加 this.OverlayChartPaint[0].MainYClose = yClose; } //获取子窗口的所有画法 this.GetChartPaint = function (windowIndex) { var paint = new Array(); for (var i in this.ChartPaint) { if (i < 3) continue; //分钟 均线 成交量 3个线不能改 var item = this.ChartPaint[i]; if (item.ChartFrame == this.Frame.SubFrame[windowIndex].Frame) paint.push(item); } return paint; } //创建指定窗口指标 this.CreateWindowIndex = function (windowIndex) { this.WindowIndex[windowIndex].Create(this, windowIndex); } this.CreateExtendChart = function (name, option) //创建扩展图形 { var chart; switch (name) { case 'MinuteTooltip': chart = new MinuteTooltipPaint(); chart.Canvas = this.Canvas; chart.ChartBorder = this.Frame.ChartBorder; chart.ChartFrame = this.Frame; chart.HQChart = this; option.LanguageID = this.LanguageID; chart.SetOption(option); this.ExtendChartPaint.push(chart); return chart; default: return null; } } this.SetMinuteInfo = function (aryInfo, bUpdate) { this.ChartInfo = []; //先清空 for (var i in aryInfo) { var infoItem = JSMinuteInfoMap.Get(aryInfo[i]); if (!infoItem) continue; var item = infoItem.Create(); this.ChartInfo.push(item); } if (bUpdate == true) this.RequestMinuteInfoData(); } this.GetChartMinuteInfo = function () { return this.ChartInfoPaint; } this.CreateMinuteInfo = function (option) //在Create()以后 在调用 { var chart = new ChartMinuteInfo(); chart.Canvas = this.Canvas; chart.ChartBorder = this.Frame.SubFrame[0].Frame.ChartBorder; chart.ChartFrame = this.Frame.SubFrame[0].Frame; chart.ChartMinutePrice = this.ChartPaint[0]; if (option && chart.SetOption) chart.SetOption(option); this.ChartInfoPaint = chart; return chart; } //信息地雷数据请求 this.RequestMinuteInfoData = function () { if (this.ChartInfo.length <= 0) return; var chart = this.GetChartMinuteInfo(); if (!chart) chart = this.CreateMinuteInfo(null); //不存在就创建 chart.SourceData = this.SourceData; //信息地雷信息 for (var i in this.ChartInfo) { this.ChartInfo[i].RequestData(this); } } //更新信息地雷 this.UpdataChartInfo = function () { var chart = this.GetChartMinuteInfo(); if (!chart) return; var infoMap = new Map(); for (var i in this.ChartInfo) { var infoData = this.ChartInfo[i].Data; for (var j in infoData) { var item = infoData[j]; var dateTime = `${item.Date} ${item.Time}`; if (infoMap.has(dateTime)) infoMap.get(dateTime).Data.push(item); else infoMap.set(dateTime, { Data: new Array(item) }); } } chart.Data = infoMap; } } //API 返回数据 转化为array[] MinuteChartContainer.JsonDataToMinuteData = function (data) { var upperSymbol = data.stock[0].symbol.toUpperCase(); var isSHSZ = MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol); var isFutures = MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol) || MARKET_SUFFIX_NAME.IsNYMEX(upperSymbol); var isSHO = MARKET_SUFFIX_NAME.IsSHO(upperSymbol); //上海股票期权 var preClose = data.stock[0].yclose; //前一个数据价格 var preAvPrice = data.stock[0].yclose; //前一个均价 var yClose = data.stock[0].yclose; if (isFutures && data.stock[0].yclearing) yClose = preClose = preAvPrice = data.stock[0].yclearing; //期货使用昨结算价 var date = data.stock[0].date; var aryMinuteData = new Array(); for (var i in data.stock[0].minute) { var jsData = data.stock[0].minute[i]; var item = new MinuteData(); if (jsData.price) preClose = jsData.price; if (jsData.avprice) preAvPrice = jsData.avprice; item.Close = jsData.price; item.Open = jsData.open; item.High = jsData.high; item.Low = jsData.low; if (isSHSZ) item.Vol = jsData.vol / 100; //原始单位股 else item.Vol = jsData.vol; item.Amount = jsData.amount; item.Increase = jsData.increase; item.Risefall = jsData.risefall; item.AvPrice = jsData.avprice; if (!item.Close) //当前没有价格 使用上一个价格填充 { item.Close = preClose; item.Open = item.High = item.Low = item.Close; } if (!item.AvPrice) item.AvPrice = preAvPrice; if (jsData.date > 0) date = jsData.date; //分钟数据中有日期 优先使用 item.DateTime = date.toString() + " " + jsData.time.toString(); item.Date = data.stock[0].date; item.Time = jsData.time; if (80) { item.Date=jsData[8]; //日期 item.DateTime=item.Date.toString()+" "+jsData[0].toString(); } if (isFutures || isSHO) item.Position = jsData.position; //期货 期权有持仓 if (i == 0) //第1个数据 写死9:25 { item.IsFristData = true; //if (isSHSZ) item.DateTime = data.stock[0].date.toString() + " 0925"; if (item.Close <= 0) //第1分钟 没数据就用开盘价 { item.Close = data.stock[0].open; item.High = item.Low = data.stock[0].open; item.AvPrice = data.stock[0].open; JSConsole.Chart.Log('[MinuteChartContainer::JsonDataToMinuteData] first minute data is empty.', data.stock[0].symbol, jsData); } } //价格是0的 都用空 if (item.Open <= 0) item.Open = null; if (item.Close <= 0) item.Close = null; if (item.AvPrice <= 0) item.AvPrice = null; if (item.High <= 0) item.High = null; if (item.Low <= 0) item.Low = null; if (yClose && item.Close) item.Increase = (item.Close - yClose) / yClose * 100; //涨幅 (最新价格-昨收)/昨收*10 aryMinuteData[i] = item; } return aryMinuteData; } //多日日线数据API 转化成array[]; MinuteChartContainer.JsonDataToMinuteDataArray = function (data) { var upperSymbol = data.symbol.toUpperCase(); var isSHSZ = MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol); var isFutures = MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol) || MARKET_SUFFIX_NAME.IsNYMEX(upperSymbol); var isSHO = MARKET_SUFFIX_NAME.IsSHO(upperSymbol); //上海股票期权 var result = []; for (var i in data.data) { var minuteData = []; var dayData = data.data[i]; var date = dayData.date; var yClose = dayData.yclose; //前收盘 计算涨幅 var preClose = yClose; //前一个数据价格 var preAvPrice=null; //前一个均价 for (var j in dayData.minute) { var jsData = dayData.minute[j]; if (jsData[2]) preClose = jsData[2]; //保存上一个收盘数据 var item = new MinuteData(); item.Close = jsData[2]; item.Open = jsData[1]; item.High = jsData[3]; item.Low = jsData[4]; if(isSHSZ) item.Vol = jsData[5] / 100; //原始单位股 else item.Vol = jsData[5]; item.Amount = jsData[6]; if (7 < jsData.length && jsData[7] > 0) { item.AvPrice = jsData[7]; //均价 preAvPrice = jsData[7]; } if (!item.Close) //当前没有价格 使用上一个价格填充 { item.Close = preClose; item.Open = item.High = item.Low = item.Close; } if (!item.AvPrice && preAvPrice) item.AvPrice = preAvPrice; if (item.Close && yClose) item.Increase = (item.Close - yClose) / yClose * 100; else item.Increase = null; item.DateTime = date.toString() + " " + jsData[0].toString(); item.Date = date; item.Time = jsData[0]; if (80) { item.Date=jsData[8]; //日期 item.DateTime=item.Date.toString()+" "+jsData[0].toString(); } if ((isFutures || isSHO) && 9 < jsData.length) item.Position = jsData[9]; //持仓 if (j == 0 ) { //if (isSHSZ) item.DateTime = date.toString() + " 0925";//第1个数据 写死9:25 item.IsFristData = true; } //价格是0的 都用空 if (item.Open <= 0) item.Open = null; if (item.Close <= 0) item.Close = null; if (item.AvPrice <= 0) item.AvPrice = null; if (item.High <= 0) item.High = null; if (item.Low <= 0) item.Low = null; if (item.AvPrice <= 0) item.AvPrice = null; minuteData[j] = item; } var newData = new ChartData(); newData.Data = minuteData; newData.YClose = yClose; newData.Close = dayData.close; newData.Date = date; result.push(newData); } return result; } /* 历史分钟走势图 */ function HistoryMinuteChartContainer(uielement) { this.newMethod = MinuteChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.HistoryMinuteApiUrl = "https://opensourcecache.zealink.com/cache/minuteday/day/"; //创建主图K线画法 this.CreateMainKLine = function () { //分钟线 var minuteLine = new ChartMinutePriceLine(); minuteLine.Canvas = this.Canvas; minuteLine.ChartBorder = this.Frame.SubFrame[0].Frame.ChartBorder; minuteLine.ChartFrame = this.Frame.SubFrame[0].Frame; minuteLine.Name = "Minute-Line"; minuteLine.Color = g_JSChartResource.Minute.PriceColor; this.ChartPaint[0] = minuteLine; //分钟线均线 var averageLine = new ChartLine(); averageLine.Canvas = this.Canvas; averageLine.ChartBorder = this.Frame.SubFrame[0].Frame.ChartBorder; averageLine.ChartFrame = this.Frame.SubFrame[0].Frame; averageLine.Name = "Minute-Average-Line"; averageLine.Color = g_JSChartResource.Minute.AvPriceColor; this.ChartPaint[1] = averageLine; var averageLine = new ChartMinuteVolumBar(); averageLine.Color = g_JSChartResource.Minute.VolBarColor; averageLine.Canvas = this.Canvas; averageLine.ChartBorder = this.Frame.SubFrame[1].Frame.ChartBorder; averageLine.ChartFrame = this.Frame.SubFrame[1].Frame; averageLine.Name = "Minute-Vol-Bar"; this.ChartPaint[2] = averageLine; this.TitlePaint[0] = new DynamicMinuteTitlePainting(); this.TitlePaint[0].Frame = this.Frame.SubFrame[0].Frame; this.TitlePaint[0].Canvas = this.Canvas; this.TitlePaint[0].IsShowDate = true; /* //主图叠加画法 var paint=new ChartOverlayKLine(); paint.Canvas=this.Canvas; paint.ChartBorder=this.Frame.SubFrame[0].Frame.ChartBorder; paint.ChartFrame=this.Frame.SubFrame[0].Frame; paint.Name="Overlay-KLine"; this.OverlayChartPaint[0]=paint; */ } //设置交易日期 this.ChangeTradeDate = function (trdateDate) { if (!trdateDate) return; this.TradeDate = trdateDate; this.RequestData(); //更新数据 } this.RequestData = function () { var date = new Date(); var nowDate = date.getFullYear() * 10000 + (date.getMonth() + 1) * 100 + date.getDate(); if (nowDate == this.TradeDate) this.RequestMinuteData(); else this.RequestHistoryMinuteData(); } //请求分钟数据 this.RequestHistoryMinuteData = function () { var self = this; var url = this.HistoryMinuteApiUrl + this.TradeDate.toString() + "/" + this.Symbol + ".json"; wx.request({ url: url, method: "get", dataType: "json", success: function (data) { self.ChartSplashPaint.EnableSplash(false); self.RecvHistoryMinuteData(data); }, error: function (reqeust) { self.ChartSplashPaint.EnableSplash(false); self.RecvHistoryMinuteError(reqeust); } }); } this.RecvHistoryMinuteError = function (reqeust) { if (reqeust.status != 404) return; var sourceData = new ChartData(); this.SourceData = sourceData; for (var i in this.ChartPaint) { this.ChartPaint[i].Data = sourceData; if (i == 0) this.ChartPaint[i].NotSupportMessage = '没有权限访问!'; } this.TitlePaint[0].Data = this.SourceData; //动态标题 this.TitlePaint[0].Symbol = this.Symbol; this.TitlePaint[0].Name = null; this.Draw(); } this.RecvHistoryMinuteData = function (recvData) { if (recvData.statusCode != 200) { var sourceData = new ChartData(); this.SourceData = sourceData; for (var i in this.ChartPaint) { this.ChartPaint[i].Data = sourceData; if (i == 0) this.ChartPaint[i].NotSupportMessage = '没有权限访问!'; } this.TitlePaint[0].Data = this.SourceData; //动态标题 this.TitlePaint[0].Symbol = this.Symbol; this.TitlePaint[0].Name = null; this.Draw(); return; } var data = recvData.data; var aryMinuteData = HistoryMinuteChartContainer.JsonDataToMinuteData(data); //原始数据 var sourceData = new ChartData(); sourceData.Data = aryMinuteData; this.TradeDate = data.date; this.SourceData = sourceData; this.Symbol = data.symbol; this.Name = data.name; this.BindMainData(sourceData, data.day.yclose); if (this.Frame.SubFrame.length > 2) { var bindData = new ChartData(); bindData.Data = aryMinuteData; for (var i = 2; i < this.Frame.SubFrame.length; ++i) { this.BindIndexData(i, bindData); } } this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); //this.AutoUpdata(); } } //API 返回数据 转化为array[] HistoryMinuteChartContainer.JsonDataToMinuteData = function (data) { var aryMinuteData = new Array(); for (var i in data.minute.time) { var item = new MinuteData(); if (data.minute.price[i] <= 0 && i > 0) //当前这一分钟价格为空,使用上一分钟的数据 { item.Close = aryMinuteData[i - 1].Close; item.Open = aryMinuteData[i - 1].Close; item.High = item.Close; item.Low = item.Close; item.Vol = data.minute.vol[i] / 100; //原始单位股 item.Amount = data.minute.amount[i]; item.DateTime = data.date.toString() + " " + data.minute.time[i].toString(); item.Date = data.date; item.Time = data.minute.time[i]; //item.Increate=jsData.increate; //item.Risefall=jsData.risefall; item.AvPrice = aryMinuteData[i - 1].AvPrice; } else { item.Close = data.minute.price[i]; item.Open = data.minute.open[i]; item.High = data.minute.high[i]; item.Low = data.minute.low[i]; item.Vol = data.minute.vol[i] / 100; //原始单位股 item.Amount = data.minute.amount[i]; item.DateTime = data.date.toString() + " " + data.minute.time[i].toString(); item.Date = data.date; item.Time = data.minute.time[i]; //item.Increate=jsData.increate; //item.Risefall=jsData.risefall; item.AvPrice = data.minute.avprice[i]; } //价格是0的 都用空 if (item.Open <= 0) item.Open = null; if (item.Close <= 0) item.Close = null; if (item.AvPrice <= 0) item.AvPrice = null; if (item.High <= 0) item.High = null; if (item.Low <= 0) item.Low = null; aryMinuteData[i] = item; } return aryMinuteData; } ///////////////////////////////////////////////////////////////////////////// // 自定义指数 // function CustomKLineChartContainer(uielement) { this.newMethod = KLineChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.ClassName = 'CustomKLineChartContainer'; this.ChangeRight = null; //没有复权设置 this.LoadDataSplashTitle = '计算指数数据'; this.CustomKLineApiUrl = g_JSChartResource.Domain + "/API/IndexCalculate"; //自定义指数计算地址 this.CustomStock; //成分 this.QueryDate = { Start: 20180101, End: 20180627 }; //计算时间区间 this.RequestHistoryData = function () { var self = this; this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle); this.ChartSplashPaint.EnableSplash(true); this.Draw(); wx.request({ url: this.CustomKLineApiUrl, data: { "stock": self.CustomStock, "Name": self.Symbol, "date": { "startdate": self.QueryDate.Start, "enddate": self.QueryDate.End } }, method: 'POST', dataType: "json", async: true, success: function (data) { self.ChartSplashPaint.EnableSplash(false); self.RecvHistoryData(data); } }); } this.RecvHistoryData = function (recvData) { var data = recvData.data; var aryDayData = KLineChartContainer.JsonDataToHistoryData(data); //原始数据 var sourceData = new ChartData(); sourceData.Data = aryDayData; sourceData.DataType = 0; //0=日线数据 1=分钟数据 sourceData.Symbol = data.symbol; //显示的数据 var bindData = new ChartData(); bindData.Data = aryDayData; bindData.Right = 0; //指数没有复权 bindData.Period = this.Period; bindData.DataType = 0; bindData.Symbol = data.symbol; if (ChartData.IsDayPeriod(this.Period, false)) //周期数据 { var periodData = sourceData.GetPeriodData(bindData.Period); bindData.Data = periodData; } //绑定数据 this.SourceData = sourceData; this.Name = data.name; this.BindMainData(bindData, this.PageSize); for (var i = 0; i < this.Frame.SubFrame.length; ++i) { this.BindIndexData(i, bindData); } //this.BindIndexData(0,hisData); //this.BindIndexData(1,hisData); //this.BindIndexData(2,hisData); //刷新画图 this.UpdataDataoffset(); //更新数据偏移 this.UpdatePointByCursorIndex(); //更新十字光标位子 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); if (typeof (this.UpdateUICallback) == 'function') this.UpdateUICallback('RecvHistoryData', this); } } //////////////////////////////////////////////////////////////////////////////// // K线横屏显示 // function KLineChartHScreenContainer(uielement) { this.newMethod = KLineChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.ClassName = 'KLineChartHScreenContainer'; this.OnMouseMove = function (x, y, e) { this.LastPoint.X = x; this.LastPoint.Y = y; this.CursorIndex = this.Frame.GetXData(y); this.DrawDynamicInfo(); } //手机拖拽 this.ontouchstart = function (e) { if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return; var jsChart = this; if (jsChart.DragMode == 0) return; jsChart.IsOnTouch = true; jsChart.PhonePinch = null; if (this.IsPhoneDragging(e)) { if (jsChart.TryClickLock || this.TryClickIndexTitle) { var touches = this.GetToucheData(e); var x = touches[0].clientX; var y = touches[0].clientY; if (jsChart.TryClickLock && jsChart.TryClickLock(x, y)) return; if (jsChart.TryClickIndexTitle && jsChart.TryClickIndexTitle(x, y)) return; } //长按2秒,十字光标 if (this.TouchTimer != null) clearTimeout(this.TouchTimer); if (this.ChartCorssCursor.IsShow == true) { this.TouchTimer = setTimeout(function () { if (drag.Click.X == drag.LastMove.X && drag.Click.Y == drag.LastMove.Y) //手指没有移动,出现十字光标 { var mouseDrag = jsChart.MouseDrag; jsChart.MouseDrag = null; //移动十字光标 var x = drag.Click.X; var y = drag.Click.Y; jsChart.OnMouseMove(x, y, e); } }, 800); } var drag = { "Click": {}, "LastMove": {}, };//最后移动的位置 var touches = this.GetToucheData(e); drag.Click.X = touches[0].clientX; drag.Click.Y = touches[0].clientY; drag.LastMove.X = touches[0].clientX; drag.LastMove.Y = touches[0].clientY; jsChart.MouseDrag = drag; } else if (this.IsPhonePinching(e)) { var phonePinch = { "Start": {}, "Last": {}}; var touches = this.GetToucheData(e); phonePinch.Start = { "X": touches[0].pageX, "Y": touches[0].pageY, "X2": touches[1].pageX, "Y2": touches[1].pageY }; phonePinch.Last = { "X": touches[0].pageX, "Y": touches[0].pageY, "X2": touches[1].pageX, "Y2": touches[1].pageY }; jsChart.PhonePinch = phonePinch; } } this.ontouchmove = function (e) { if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return; var jsChart = this; var touches = this.GetToucheData(e); if (this.IsPhoneDragging(e)) { var drag = jsChart.MouseDrag; if (drag == null) { var x = touches[0].clientX; var y = touches[0].clientY; jsChart.OnMouseMove(x, y, e); } else { var moveSetp = Math.abs(drag.LastMove.Y - touches[0].clientY); moveSetp = parseInt(moveSetp); if (jsChart.DragMode == 1) //数据左右拖拽 { if (moveSetp < 5) return; var isLeft = true; if (drag.LastMove.Y < touches[0].clientY) isLeft = false;//右移数据 if (jsChart.DataMove(moveSetp, isLeft)) { jsChart.UpdataDataoffset(); jsChart.UpdatePointByCursorIndex(); jsChart.UpdateFrameMaxMin(); jsChart.ResetFrameXYSplit(); jsChart.Draw(); } drag.LastMove.X = touches[0].clientX; drag.LastMove.Y = touches[0].clientY; } } } else if (this.IsPhonePinching(e)) { var phonePinch = jsChart.PhonePinch; if (!phonePinch) return; if (this.EnableZoomUpDown && this.EnableZoomUpDown.Touch===false) return; var yHeight = Math.abs(touches[0].pageX - touches[1].pageX); var yLastHeight = Math.abs(phonePinch.Last.X - phonePinch.Last.X2); var yStep = yHeight - yLastHeight; if (Math.abs(yStep) < 5) return; if (yStep > 0) //放大 { var cursorIndex = {}; cursorIndex.Index = parseInt(Math.abs(jsChart.CursorIndex - 0.5).toFixed(0)); if (!jsChart.Frame.ZoomUp(cursorIndex)) return; jsChart.CursorIndex = cursorIndex.Index; jsChart.UpdatePointByCursorIndex(); jsChart.UpdataDataoffset(); jsChart.UpdateFrameMaxMin(); jsChart.ResetFrameXYSplit(); jsChart.Draw(); } else //缩小 { var cursorIndex = {}; cursorIndex.Index = parseInt(Math.abs(jsChart.CursorIndex - 0.5).toFixed(0)); if (!jsChart.Frame.ZoomDown(cursorIndex)) return; jsChart.CursorIndex = cursorIndex.Index; jsChart.UpdataDataoffset(); jsChart.UpdatePointByCursorIndex(); jsChart.UpdateFrameMaxMin(); jsChart.ResetFrameXYSplit(); jsChart.Draw(); } phonePinch.Last = { "X": touches[0].pageX, "Y": touches[0].pageY, "X2": touches[1].pageX, "Y2": touches[1].pageY }; } } uielement.onmousedown = function (e) //鼠标拖拽 { if (!this.JSChartContainer) return; if (this.JSChartContainer.DragMode == 0) return; if (this.JSChartContainer.TryClickLock) { var x = e.clientX - this.getBoundingClientRect().left; var y = e.clientY - this.getBoundingClientRect().top; if (this.JSChartContainer.TryClickLock(x, y)) return; } var drag = { "Click": {}, "LastMove": {}, //最后移动的位置 }; drag.Click.X = e.clientX; drag.Click.Y = e.clientY; drag.LastMove.X = e.clientX; drag.LastMove.Y = e.clientY; this.JSChartContainer.MouseDrag = drag; document.JSChartContainer = this.JSChartContainer; this.JSChartContainer.SelectChartDrawPicture = null; uielement.ondblclick = function (e) { var x = e.clientX - this.getBoundingClientRect().left; var y = e.clientY - this.getBoundingClientRect().top; if (this.JSChartContainer) this.JSChartContainer.OnDoubleClick(x, y, e); } document.onmousemove = function (e) { if (!this.JSChartContainer) return; //加载数据中,禁用鼠标事件 if (this.JSChartContainer.ChartSplashPaint && this.JSChartContainer.ChartSplashPaint.IsEnableSplash == true) return; var drag = this.JSChartContainer.MouseDrag; if (!drag) return; var moveSetp = Math.abs(drag.LastMove.Y - e.clientY); if (this.JSChartContainer.DragMode == 1) //数据左右拖拽 { if (moveSetp < 5) return; var isLeft = true; if (drag.LastMove.Y < e.clientY) isLeft = false;//右移数据 if (this.JSChartContainer.DataMove(moveSetp, isLeft)) { this.JSChartContainer.UpdataDataoffset(); this.JSChartContainer.UpdatePointByCursorIndex(); this.JSChartContainer.UpdateFrameMaxMin(); this.JSChartContainer.ResetFrameXYSplit(); this.JSChartContainer.Draw(); } drag.LastMove.X = e.clientX; drag.LastMove.Y = e.clientY; } }; document.onmouseup = function (e) { //清空事件 document.onmousemove = null; document.onmouseup = null; //清空数据 this.JSChartContainer.MouseDrag = null; this.JSChartContainer.CurrentChartDrawPicture = null; this.JSChartContainer = null; } } //创建 //windowCount 窗口个数 this.Create = function (windowCount) { this.UIElement.JSChartContainer = this; //创建十字光标 this.ChartCorssCursor = new ChartCorssCursor(); this.ChartCorssCursor.Canvas = this.Canvas; this.ChartCorssCursor.StringFormatX = g_DivTooltipDataForamt.Create("CorssCursor_XStringFormat"); this.ChartCorssCursor.StringFormatX.LanguageID=this.LanguageID; this.ChartCorssCursor.StringFormatY = g_DivTooltipDataForamt.Create("CorssCursor_YStringFormat"); this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID; //创建等待提示 this.ChartSplashPaint = new ChartSplashPaint(); this.ChartSplashPaint.Canvas = this.Canvas; this.ChartSplashPaint.HQChart=this; //创建框架容器 this.Frame = new HQTradeHScreenFrame(); this.Frame.ChartBorder = new ChartBorder(); this.Frame.ChartBorder.UIElement = this.UIElement; this.Frame.ChartBorder.Top = 30; this.Frame.ChartBorder.Left = 5; this.Frame.ChartBorder.Bottom = 20; this.Frame.Canvas = this.Canvas; this.ChartCorssCursor.Frame = this.Frame; //十字光标绑定框架 this.ChartSplashPaint.Frame = this.Frame; this.CreateChildWindow(windowCount); this.CreateMainKLine(); //子窗口动态标题 for (var i in this.Frame.SubFrame) { var titlePaint = new DynamicChartTitlePainting(); titlePaint.Frame = this.Frame.SubFrame[i].Frame; titlePaint.Canvas = this.Canvas; this.TitlePaint.push(titlePaint); } } //创建子窗口 this.CreateChildWindow = function (windowCount) { for (var i = 0; i < windowCount; ++i) { var border = new ChartBorder(); border.UIElement = this.UIElement; var frame = new KLineHScreenFrame(); frame.Canvas = this.Canvas; frame.ChartBorder = border; frame.Identify = i; //窗口序号 frame.RightSpaceCount = this.RightSpaceCount; //右边 if (this.ModifyIndexDialog) frame.ModifyIndexEvent = this.ModifyIndexDialog.DoModal; //绑定菜单事件 if (this.ChangeIndexDialog) frame.ChangeIndexEvent = this.ChangeIndexDialog.DoModal; frame.HorizontalMax = 20; frame.HorizontalMin = 10; if (i == 0) { frame.YSplitOperator = new FrameSplitKLinePriceY(); frame.YSplitOperator.FrameSplitData = this.FrameSplitData.get('price'); //主图上下间距 border.TopSpace = 12; border.BottomSpace = 12; } else { frame.YSplitOperator = new FrameSplitY(); frame.YSplitOperator.FrameSplitData = this.FrameSplitData.get('double'); //frame.IsLocked = true; } frame.YSplitOperator.Frame = frame; frame.YSplitOperator.ChartBorder = border; frame.XSplitOperator = new FrameSplitKLineX(); frame.XSplitOperator.Frame = frame; frame.XSplitOperator.ChartBorder = border; if (i != windowCount - 1) frame.XSplitOperator.ShowText = false; for (var j = frame.HorizontalMin; j <= frame.HorizontalMax; j += 1) { frame.HorizontalInfo[j] = new CoordinateInfo(); frame.HorizontalInfo[j].Value = j; if (i == 0 && j == frame.HorizontalMin) continue; frame.HorizontalInfo[j].Message[1] = j.toString(); frame.HorizontalInfo[j].Font = "14px 微软雅黑"; } var subFrame = new SubFrameItem(); subFrame.Frame = frame; if (i == 0) subFrame.Height = 20; else subFrame.Height = 10; this.Frame.SubFrame[i] = subFrame; } } } //////////////////////////////////////////////////////////////////////////////// // 走势图横屏显示 // function MinuteChartHScreenContainer(uielement) { this.newMethod = MinuteChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.ClassName = 'MinuteChartHScreenContainer'; this.OnMouseMove = function (x, y, e) { this.LastPoint.X = x; this.LastPoint.Y = y; this.CursorIndex = this.Frame.GetXData(y); this.DrawDynamicInfo(); } //创建 //windowCount 窗口个数 this.Create = function (windowCount) { this.UIElement.JSChartContainer = this; //创建十字光标 this.ChartCorssCursor = new ChartCorssCursor(); this.ChartCorssCursor.Canvas = this.Canvas; this.ChartCorssCursor.StringFormatX = new HQMinuteTimeStringFormat(); this.ChartCorssCursor.StringFormatY = new HQPriceStringFormat(); //创建等待提示 this.ChartSplashPaint = new ChartSplashPaint(); this.ChartSplashPaint.Canvas = this.Canvas; this.ChartSplashPaint.SplashTitle = this.LoadDataSplashTitle; //创建框架容器 this.Frame = new HQTradeHScreenFrame(); this.Frame.ChartBorder = new ChartBorder(); this.Frame.ChartBorder.UIElement = this.UIElement; this.Frame.ChartBorder.Top = 25; this.Frame.ChartBorder.Left = 50; this.Frame.ChartBorder.Bottom = 20; this.Frame.Canvas = this.Canvas; this.ChartCorssCursor.Frame = this.Frame; //十字光标绑定框架 this.ChartSplashPaint.Frame = this.Frame; this.CreateChildWindow(windowCount); this.CreateMainKLine(); //子窗口动态标题 for (var i in this.Frame.SubFrame) { var titlePaint = new DynamicChartTitlePainting(); titlePaint.Frame = this.Frame.SubFrame[i].Frame; titlePaint.Canvas = this.Canvas; this.TitlePaint.push(titlePaint); } this.ChartCorssCursor.StringFormatX.Frame = this.Frame.SubFrame[0].Frame; } //创建子窗口 this.CreateChildWindow = function (windowCount) { for (var i = 0; i < windowCount; ++i) { var border = new ChartBorder(); border.UIElement = this.UIElement; var frame = new MinuteHScreenFrame(); frame.Canvas = this.Canvas; frame.ChartBorder = border; if (i < 2) frame.ChartBorder.TitleHeight = 0; frame.XPointCount = 243; var DEFAULT_HORIZONTAL = [9, 8, 7, 6, 5, 4, 3, 2, 1]; frame.HorizontalMax = DEFAULT_HORIZONTAL[0]; frame.HorizontalMin = DEFAULT_HORIZONTAL[DEFAULT_HORIZONTAL.length - 1]; if (i == 0) { frame.YSplitOperator = new FrameSplitMinutePriceY(); frame.YSplitOperator.FrameSplitData = this.FrameSplitData.get('price'); } else { frame.YSplitOperator = new FrameSplitY(); frame.YSplitOperator.FrameSplitData = this.FrameSplitData.get('double'); } frame.YSplitOperator.Frame = frame; frame.YSplitOperator.ChartBorder = border; frame.XSplitOperator = new FrameSplitMinuteX(); frame.XSplitOperator.Frame = frame; frame.XSplitOperator.ChartBorder = border; if (i != windowCount - 1) frame.XSplitOperator.ShowText = false; frame.XSplitOperator.Operator(); for (var j in DEFAULT_HORIZONTAL) { frame.HorizontalInfo[j] = new CoordinateInfo(); frame.HorizontalInfo[j].Value = DEFAULT_HORIZONTAL[j]; if (i == 0 && j == frame.HorizontalMin) continue; frame.HorizontalInfo[j].Message[1] = DEFAULT_HORIZONTAL[j].toString(); frame.HorizontalInfo[j].Font = "14px 微软雅黑"; } var subFrame = new SubFrameItem(); subFrame.Frame = frame; if (i == 0) subFrame.Height = 20; else subFrame.Height = 10; this.Frame.SubFrame[i] = subFrame; } } } //////////////////////////////////////////////////////////////////////////////// // K线训练,包含横屏 // function KLineTrainChartContainer(uielement, bHScreen) { if (bHScreen === true) { this.newMethod = KLineChartHScreenContainer; //派生 this.newMethod(uielement); delete this.newMethod; } else { this.newMethod = KLineChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; } this.ClassName2 = 'KLineTrainChartContainer'; this.BuySellPaint; //买卖点画法 this.TrainDataCount = 300; //训练数据个数 this.AutoRunTimer = null; //K线自动前进定时器 this.BuySellData = []; //模拟买卖数据 {Buy:{Price:价格,Date:日期,Time:时间} , Sell:{Price:价格,Date:日期,Time:时间} this.TrainDataIndex; //当前训练的数据索引 this.TrainCallback; //训练回调 (K线每前进一次就调用一次) this.DragMode = 1; this.TrainStartEnd = {}; this.KLineSourceData; //原始K线数据 对应 SourceData this.TrainInfo = { Start: {}, End: {} }; // Index:数据索引, Date:日期 Time:时间 this.CreateBuySellPaint = function () //在主窗口建立以后 创建买卖点 { var chart = new ChartBuySell(); chart.Canvas = this.Canvas; chart.ChartBorder = this.Frame.SubFrame[0].Frame.ChartBorder; chart.ChartFrame = this.Frame.SubFrame[0].Frame; chart.Name = "KLine-Train-BuySell"; this.ChartPaintEx[0] = chart; } this.GetKDataIndexByDateTime = function (kData, dateTime) { if (!dateTime || !kData) return -1; for (var i in kData) { var item = kData[i]; if (ChartData.IsMinutePeriod(this.Period, true)) { if (IFrameSplitOperator.IsNumber(this.TrainStartDate.Time)) { if (item.Date >= this.TrainStartDate.Date && item.Time >= this.TrainStartDate.Time) return parseInt(i); } else { if (item.Date >= this.TrainStartDate.Date) return parseInt(i); } } else if (ChartData.IsDayPeriod(this.Period, true) || ChartData.IsTickPeriod(this.Period)) { if (item.Date >= this.TrainStartDate.Date) return parseInt(i); } } return -1; } this.AfterBindMainData = function (funcName) { if (!this.ChartPaintEx[0]) this.CreateBuySellPaint(); var hisData = this.ChartPaint[0].Data; this.ChartPaintEx[0].Data = hisData; var showItem = hisData.Data[hisData.Data.length - 1]; //最后一个显示数据 this.TrainInfo.LastShowData = showItem; //最后一个原始数据 this.TrainInfo.LastData = this.SourceData.Data[this.SourceData.Data.length - 1]; if (funcName != 'Update') this.UpdateTrainUICallback("开始"); } this.BeforeBindMainData = function (funcName) { if (funcName == "Update") return; //全量数据 需要过滤 this.KLineSourceData = new ChartData(); this.KLineSourceData.Data = this.SourceData.Data.slice(0); var count = this.SourceData.Data.length; var lEnd = count - this.TrainDataCount - 20; var findIndex = this.GetKDataIndexByDateTime(this.SourceData.Data, this.TrainStartDate); if (findIndex >= 0) { lEnd = findIndex + 1; if (count - lEnd < this.TrainDataCount) this.TrainDataCount = count - lEnd; } //训练起始日期 var index = lEnd - 1; var kItem = this.SourceData.Data[index]; this.TrainInfo.Start.Index = index; this.TrainInfo.Start.Date = kItem.Date; this.TrainInfo.Start.Time = kItem.Time; //训练结束日期 this.TrainInfo.End.Index = index; this.TrainInfo.End.Date = kItem.Date; this.TrainInfo.End.Time = kItem.Time; //最后一个数据 this.TrainInfo.LastData = kItem; //修改数据个数 this.SourceData.Data.length = lEnd; } this.Run = function (option) { if (this.AutoRunTimer) return; if (this.TrainDataCount <= 0) return; var self = this; this.AutoRunTimer = setInterval(function () { if (!self.MoveNextKLineData(option)) clearInterval(self.AutoRunTimer); }, 1000); } this.MoveNextKLineData = function (option) //{PageSize:, Step:} { if (this.TrainDataCount <= 0) return false; var step = 1, moveStep=0; if (option && option.Step > 1) step = option.Step; for (var i = 0; i < step; ++i) { var index = this.TrainInfo.End.Index + 1; if (index >= this.KLineSourceData.Data.length) break; var kItem = this.KLineSourceData.Data[index]; this.SourceData.Data.push(kItem); this.TrainInfo.End.Index = index; this.TrainInfo.End.Date = kItem.Date; this.TrainInfo.End.Time = kItem.Time; --this.TrainDataCount; ++moveStep; if (this.TrainDataCount <= 0) break; } if (moveStep == 0) return false; //使用当前页数据个数移动K线 var pageSize = this.Frame.GetCurrentPageSize(); if (IFrameSplitOperator.IsNumber(pageSize)) this.PageSize = pageSize - this.RightSpaceCount; this.Update(); if (this.TrainDataCount <= 0) { this.FinishTrainData(); this.UpdateTrainUICallback("结束"); return false; } this.UpdateTrainUICallback("训练中"); return true; } this.UpdateTrainUICallback = function (description) { //新的监听事件 if (!this.mapEvent.has(JSCHART_EVENT_ID.RECV_TRAIN_MOVE_STEP)) return; var item = this.mapEvent.get(JSCHART_EVENT_ID.RECV_TRAIN_MOVE_STEP); if (!item.Callback) return; var data = { TrainDataCount: this.TrainDataCount, BuySellData: this.BuySellData, KLine: { Start: { Index: this.TrainInfo.Start.Index, Date: this.TrainInfo.Start.Date }, End: { Index: this.TrainInfo.End.Index, Date: this.TrainInfo.End.Date } }, LastData: this.TrainInfo.LastData, LastShowData: this.TrainInfo.LastShowData }; if (IFrameSplitOperator.IsNumber(this.TrainInfo.Start.Time)) data.KLine.Start.Time = this.TrainInfo.Start.Time; if (IFrameSplitOperator.IsNumber(this.TrainInfo.End.Time)) data.KLine.End.Time = this.TrainInfo.End.Time; if (description) data.Description = description if (this.TrainDataCount <= 0) { data.Symbol = this.Symbol; data.Name = this.Name; } item.Callback(item, data, this); } this.FinishTrainData = function () { } this.Stop = function () { if (this.AutoRunTimer != null) clearInterval(this.AutoRunTimer); this.AutoRunTimer = null; } this.BuyOrSell = function (obj, bDraw) //{ Price:价格, Vol:数量, Op: 买/卖 0=buy 1=sell, ID:单号 } bDraw是否立即绘制图标 { var kItem = this.TrainInfo.LastShowData; if (!kItem) return false; var buySellPaint = this.ChartPaintEx[0]; if (!buySellPaint) return false; var hisData = this.ChartPaint[0].Data; if (!hisData || hisData.Data.length <= 0) return false; var index = hisData.Data.length - 1; //数据索引 var buyItem = { Date: this.TrainInfo.End.Date, Time: this.TrainInfo.End.Time, Price: obj.Price, Vol: obj.Vol, Op: 0, ID: obj.ID }; if (obj.Op == 1) buyItem.Op = 1; var key = index; buyItem.Key = key; this.BuySellData.push(buyItem); buySellPaint.AddTradeItem(buyItem); if (bDraw == true) this.Draw(); } this.RestartTrain = function (option) // { Symbol:, Period:周期, Right:复权, Train:{ DataCount:, DateTime: } } { JSConsole.Chart.Log('[KLineTrainChartContainer::RestartTrain] option ', option); this.TrainInfo = { Start: {}, End: {} }; this.BuySellData = []; this.KLineSourceData = null; var buySellPaint = this.ChartPaintEx[0]; if (buySellPaint) { buySellPaint.Data = null; buySellPaint.ClearTradeData(); } if (option.Symbol) this.Symbol = option.Symbol; if (IFrameSplitOperator.IsNumber(option.Period)) this.Period = option.Period; if (IFrameSplitOperator.IsNumber(option.Right)) this.Right = option.Right; if (option.Train) { if (option.Train.DataCount > 1) this.TrainDataCount = option.Train.DataCount; if (option.Train.DateTime) this.TrainStartDate = option.Train.DateTime; } var symbol = this.Symbol; this.ChangeSymbol(symbol); } } ///////////////////////////////////////////////////////////////////////////////// // 深度图 // function DepthChartContainer(uielement) { this.newMethod=JSChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.ClassName="DepthChartContainer"; this.Symbol; //数据 this.MapAsk=new Map(); this.MapBid=new Map(); this.IsAutoUpdate=false; //是否自动更新行情数据 this.AutoUpdateFrequency=30000; //30秒更新一次数据 this.AutoUpdateTimer; this.DefaultZoom=0.8; //默认显示80%的盘口 (0 - 1) this.MaxVolRate=1.1; this.Create=function(option) { this.UIElement.JSChartContainer=this; //创建十字光标 this.ChartCorssCursor=new DepthChartCorssCursor(); this.ChartCorssCursor.Canvas=this.Canvas; this.ChartCorssCursor.HQChart=this; //this.ChartCorssCursor.StringFormatX=g_DivTooltipDataForamt.Create("CorssCursor_XStringFormat"); //this.ChartCorssCursor.StringFormatX.LanguageID=this.LanguageID; //this.ChartCorssCursor.StringFormatY=g_DivTooltipDataForamt.Create("CorssCursor_YStringFormat"); //this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID; //创建等待提示 this.ChartSplashPaint = new ChartSplashPaint(); this.ChartSplashPaint.Canvas = this.Canvas; //创建框架 this.Frame=new DepthChartFrame(); this.Frame.ChartBorder=new ChartBorder(); this.Frame.ChartBorder.UIElement=this.UIElement; this.Frame.ChartBorder.Top=30; this.Frame.ChartBorder.Left=5; this.Frame.ChartBorder.Bottom=20; this.Frame.ChartBorder.TitleHeight=0; this.Frame.Canvas=this.Canvas; var ySplitOper=new FrameSplitY(); ySplitOper.FrameSplitData=this.FrameSplitData.get('double'); ySplitOper.LanguageID=this.LanguageID; ySplitOper.Frame=this.Frame; ySplitOper.SplitCount=5; ySplitOper.IgnoreYValue=[0]; ySplitOper.LineType=3; ySplitOper.ChartBorder=this.Frame.ChartBorder; this.Frame.YSplitOperator=ySplitOper; var xSplitOper=new FrameSplitXDepth(); xSplitOper.Frame=this.Frame;; xSplitOper.ChartBorder=this.Frame.ChartBorder;; xSplitOper.LanguageID=this.LanguageID; xSplitOper.LineType=3; this.Frame.XSplitOperator=xSplitOper if (this.ChartCorssCursor) this.ChartCorssCursor.Frame=this.Frame; //十字光标绑定框架 this.ChartSplashPaint.Frame = this.Frame; var chartItem=new ChartOrderbookDepth(); chartItem.Canvas=this.Canvas; chartItem.ChartBorder=this.Frame.ChartBorder; chartItem.ChartFrame=this.Frame; chartItem.Name="深度图" this.ChartPaint.push(chartItem); } this.ontouchstart=function(e) { this.IsOnTouch=true; this.TouchDrawCount=0; this.PhonePinch=null; var isSingleTouch=this.IsSingleTouch(e); if (this.EnableScrollUpDown==false || !isSingleTouch) //多点触屏 { } if (this.IsPhoneDragging(e)) { var drag= { "Click":{}, "LastMove":{} //最后移动的位置 }; var touches=this.GetToucheData(e,this.IsForceLandscape); drag.Click.X=touches[0].clientX; drag.Click.Y=touches[0].clientY; drag.LastMove.X=touches[0].clientX; drag.LastMove.Y=touches[0].clientY; this.MouseDrag=drag; var x = drag.Click.X; var y = drag.Click.Y; this.OnMouseMove(x, y, e); } else if (this.IsPhonePinching(e)) { var phonePinch= { "Start":{}, "Last":{} }; var touches=this.GetToucheData(e,this.IsForceLandscape); phonePinch.Start={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY}; phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY}; this.PhonePinch=phonePinch; } } this.ontouchmove=function(e) { var touches=this.GetToucheData(e,false); if (this.IsPhoneDragging(e)) { var drag=this.MouseDrag; if (drag==null) { var x = touches[0].clientX; var y = touches[0].clientY; this.OnMouseMove(x,y,e); } else { this.MouseDrag=null; var x = touches[0].clientX; var y = touches[0].clientY; this.OnMouseMove(x,y,e); } } else if (this.IsPhonePinching(e)) { var phonePinch=this.PhonePinch; if (!phonePinch) return; if (this.EnableZoomUpDown && this.EnableZoomUpDown.Touch===false) return; var yHeight = Math.abs(touches[0].pageY - touches[1].pageY); var yLastHeight = Math.abs(phonePinch.Last.Y - phonePinch.Last.Y2); var yStep = yHeight - yLastHeight; var xHeight = Math.abs(touches[0].pageX - touches[1].pageX); var xLastHeight = Math.abs(phonePinch.Last.X - phonePinch.Last.X2); var xStep = xHeight - xLastHeight; var minStep=this.ZoomStepPixel; if (Math.abs(yStep) 0) //放大 { if (!this.Frame.ZoomUp()) return; this.UpdateFrameMaxMin(); this.Draw(); } else //缩小 { if (!this.Frame.ZoomDown()) return; this.UpdateFrameMaxMin(); this.Draw(); } phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY}; } } this.ontouchend=function(e) { JSConsole.Chart.Log('[DepthChartContainer::OnTouchEnd]',e); this.IsOnTouch = false; this.Draw(); this.TouchDrawCount=0; } this.OnMouseMove = function (x, y, e, bFullDraw) { var lastY = this.LastPoint.Y; this.LastPoint.X = x; this.LastPoint.Y = y; this.FullDraw(); } this.ChangeSymbol=function(symbol) { this.CancelAutoUpdate(); //先停止定时器 this.Symbol=symbol; this.MapBid=new Map(); this.MapAsk=new Map(); this.Frame.VerticalRange.Differ=null; this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle); this.ChartSplashPaint.EnableSplash(true); this.Draw(); this.RequestDepthData(); } this.RequestDepthData=function() //全量历史数据 { var self=this; if (this.NetworkFilter) { var obj= { Name:'DepthChartContainer::RequestDepthData', //类名:: Explain:'深度图数据', Request:{ Data: { symbol:self.Symbol } }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.ChartSplashPaint.EnableSplash(false); self.RecvDepthData(data); self.AutoUpdate(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } } this.RecvDepthData=function(data) { this.UpdateAskAndBid(data); var aryAsk=Array.from(this.MapAsk.values()); //卖 右边 aryAsk.sort((a,b)=> { return a.Price-b.Price; }); var sumVol=0; for(var i in aryAsk) { var item=aryAsk[i]; sumVol+=item.Vol; aryAsk[i]={Price:item.Price, Vol:sumVol }; } var aryBid=Array.from(this.MapBid.values()); //买 左边 aryBid.sort((a,b)=> { return b.Price-a.Price; }); var sumVol=0; for(var i in aryBid) { var item=aryBid[i]; sumVol+=item.Vol; aryBid[i]={Price:item.Price, Vol:sumVol }; } var drawData={ Asks:aryAsk, Bids:aryBid }; var chart=this.ChartPaint[0]; chart.Data=drawData; this.Frame.XSplitOperator.Symbol=this.Symbol; this.ChartCorssCursor.Data=drawData; this.ChartCorssCursor.Symbol=this.Symbol; this.UpdateFramePriceList(); this.UpdateFrameMaxMin(); this.Draw(); } this.UpdateAskAndBid=function(data) //更新数据 { if(data.datatype=="snapshot") //全量数据 { this.MapBid=new Map(); this.MapAsk=new Map(); } for(var i in data.asks) { var item=data.asks[i]; var price=parseFloat(item[0]); var vol=parseFloat(item[1]); if (this.MapAsk.has(price)) { var value=this.MapAsk.get(price); if (vol<=0) this.MapAsk.delete(price); else value.Vol=vol; } else { if (vol>0) this.MapAsk.set(price, { Price:price, Vol:vol}); } } for(var i in data.bids) { var item=data.bids[i]; var price=parseFloat(item[0]); var vol=parseFloat(item[1]); if (this.MapBid.has(price)) { var value=this.MapBid.get(price); if (vol<=0) this.MapBid.delete(price); else value.Vol=vol; } else { if (vol>0) this.MapBid.set(price, { Price:price, Vol:vol}); } } } this.UpdateFramePriceList=function() { var aryAskPrice=Array.from(this.MapAsk.keys()); var aryBidPrice=Array.from(this.MapBid.keys()); aryAskPrice.sort((a,b)=> { return a-b; }); aryBidPrice.sort((a,b)=> { return a-b; }); if (aryAskPrice.length>1 && aryBidPrice.length>1) { var askMin=aryAskPrice[0], askMax=aryAskPrice[aryAskPrice.length-1]; var bidMin=aryBidPrice[0], bidMax=aryBidPrice[aryBidPrice.length-1]; var askDifference=askMax-askMin; //卖差值 var bidDifference=bidMax-bidMin; //买差值 var difference=Math.max(askDifference, bidDifference); //取最大的差值,2边调整 var ask={Min:askMin, Max:askMin+difference}; var bid={Max:bidMax, Min:bidMax-difference}; var range={ Max:ask.Max, Min:bid.Min }; } this.Frame.SetPriceList(aryAskPrice,aryBidPrice); var xRange=this.Frame.VerticalRange; xRange.Max=range.Max; xRange.Center=range.Min+(range.Max-range.Min)/2; xRange.Min=range.Min; xRange.MaxDiffer=difference; //差值 xRange.Ask=ask; xRange.Bid=bid; if (!IFrameSplitOperator.IsNumber(xRange.Differ)) xRange.Differ=difference*this.DefaultZoom; xRange.Min=xRange.Center-xRange.Differ; xRange.Max=xRange.Center+xRange.Differ; } this.UpdateFrameMaxMin=function() { var range=this.ChartPaint[0].GetMaxMin(); this.Frame.HorizontalMax=range.Max*this.MaxVolRate; this.Frame.HorizontalMin=0; this.Frame.XYSplit=true; } this.CancelAutoUpdate=function() //关闭停止更新 { if (typeof (this.AutoUpdateTimer) == 'number') { clearTimeout(this.AutoUpdateTimer); this.AutoUpdateTimer = undefined; } } this.StopAutoUpdate=function() { this.CancelAutoUpdate(); if (!this.IsAutoUpdate) return; this.IsAutoUpdate=false; } this.AutoUpdate=function() //数据自动更新 { this.CancelAutoUpdate(); if (!this.IsAutoUpdate) return; if (!this.Symbol) return; if (this.IsDestroy) return; var self = this; var marketStatus=MARKET_SUFFIX_NAME.GetMarketStatus(this.Symbol); if (marketStatus==0 || marketStatus==3) return; //闭市,盘后 var frequency=this.AutoUpdateFrequency; if (marketStatus==1) //盘前 { this.AutoUpdateTimer=setTimeout(function() { self.AutoUpdate(); },frequency); } else if (marketStatus==2) //盘中 { this.AutoUpdateTimer=setTimeout(function() { self.RequestDepthData(); },frequency); } } } //////////////////////////////////////////////////////////////////////////////// // 简单的图形框架 // function SimlpleChartContainer(uielement) { this.newMethod = JSChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.WindowIndex = new Array(); this.MainDataControl; //主数据类(对外的接口类) this.SubDataControl = new Array(); this.FrameType = 0; //框架类型 this.YSplitCount = 4; //创建 this.Create = function () { this.UIElement.JSChartContainer = this; //创建十字光标 //this.ChartCorssCursor=new ChartCorssCursor(); //this.ChartCorssCursor.Canvas=this.Canvas; //this.ChartCorssCursor.StringFormatX=new HQDateStringFormat(); //this.ChartCorssCursor.StringFormatY=new HQPriceStringFormat(); //创建等待提示 this.ChartSplashPaint = new ChartSplashPaint(); this.ChartSplashPaint.Canvas = this.Canvas; //创建框架容器 if (this.FrameType == 1) this.Frame = new Rotate90SimpleChartFrame(); else this.Frame = new SimpleChartFrame(); this.Frame.ChartBorder = new ChartBorder(); this.Frame.ChartBorder.UIElement = this.UIElement; this.Frame.ChartBorder.Top = 30; this.Frame.ChartBorder.Left = 5; this.Frame.ChartBorder.Bottom = 20; this.Frame.Canvas = this.Canvas; if (this.ChartCorssCursor) this.ChartCorssCursor.Frame = this.Frame; //十字光标绑定框架 this.ChartSplashPaint.Frame = this.Frame; this.CreateMainChart(); } this.SetMainDataConotrl = function (dataControl) { if (!dataControl) return; this.MainDataControl = dataControl; this.ChartPaint = []; //图形 this.Frame.BarCount = 0; let yStringFormat = this.Frame.YSplitOperator.StringFormat;//保存配置 this.CreateMainChart(); this.Frame.YSplitOperator.StringFormat = yStringFormat;//还原配置 this.Draw(); this.RequestData(); } //创建主数据画法 this.CreateMainChart = function () { if (!this.MainDataControl) return; let barIndex = 0; for (let i in this.MainDataControl.DataType) { let item = this.MainDataControl.DataType[i]; if (item.Type == "BAR") { let chartItem; if (this.FrameType == 1) chartItem = new ChartXYSubBar(); else chartItem = new ChartSubBar(); chartItem.BarID = barIndex; chartItem.Canvas = this.Canvas; chartItem.ChartBorder = this.Frame.ChartBorder; chartItem.ChartFrame = this.Frame; chartItem.Name = item.Name; if (item.Color) chartItem.UpBarColor = item.Color; if (item.Color2) chartItem.DownBarColor = item.Color2; this.ChartPaint.push(chartItem); ++this.Frame.BarCount; ++barIndex; } else if (item.Type == "LINE") { let chartItem = new ChartLine(); chartItem.Canvas = this.Canvas; chartItem.ChartBorder = this.Frame.ChartBorder; chartItem.ChartFrame = this.Frame; chartItem.Name = item.Name; if (item.Color) chartItem.Color = item.Color; this.ChartPaint.push(chartItem); } } var floatPrecision = 2; //设置纵坐标的小数位数 默认为2 var ignoreYValue=null if (this.Frame.YSplitOperator) { floatPrecision = this.Frame.YSplitOperator.FloatPrecision; //备份上次实例化的值 if (this.Frame.YSplitOperator.IgnoreYValue) ignoreYValue = this.Frame.YSplitOperator.IgnoreYValue; } this.Frame.YSplitOperator = new FrameSplitY(); this.Frame.YSplitOperator.FloatPrecision = floatPrecision; //实例化纵坐标分割后 赋给备份的值 this.Frame.YSplitOperator.IgnoreYValue = ignoreYValue; this.Frame.YSplitOperator.SplitCount = this.YSplitCount; this.Frame.YSplitOperator.FrameSplitData = this.FrameSplitData.get('double'); this.Frame.YSplitOperator.Frame = this.Frame; this.Frame.YSplitOperator.ChartBorder = this.Frame.ChartBorder; this.Frame.XSplitOperator = new FrameSplitXData(); this.Frame.XSplitOperator.Frame = this.Frame; this.Frame.XSplitOperator.ChartBorder = this.Frame.ChartBorder; // this.TitlePaint[0]=new DynamicKLineTitlePainting(); // this.TitlePaint[0].Frame=this.Frame.SubFrame[0].Frame; // this.TitlePaint[0].Canvas=this.Canvas; } this.RequestData = function () { if (!this.MainDataControl) return; this.MainDataControl.JSChartContainer = this; this.MainDataControl.RequestData(); } this.UpdateMainData = function (dataControl) { let lCount = 0; for (let i in dataControl.Data) { let itemData = new ChartData(); itemData.Data = dataControl.Data[i]; this.ChartPaint[i].Data = itemData; if (lCount < itemData.Data.length) lCount = itemData.Data.length; } this.Frame.XPointCount = lCount; this.Frame.Data = this.ChartPaint[0].Data; this.Frame.XData = dataControl.XData; this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } } //////////////////////////////////////////////////////////////////////////////// // 饼图图形框架 // function PieChartContainer(uielement) { this.Radius; //半径 this.newMethod = JSChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.MainDataControl; //主数据类(对外的接口类) //鼠标移动 this.OnMouseMove = function (x, y, e) { } //创建 this.Create = function () { this.UIElement.JSChartContainer = this; //创建等待提示 this.ChartSplashPaint = new ChartSplashPaint(); this.ChartSplashPaint.Canvas = this.Canvas; //创建框架容器 this.Frame = new NoneFrame(); this.Frame.ChartBorder = new ChartBorder(); this.Frame.ChartBorder.UIElement = this.UIElement; this.Frame.ChartBorder.Top = 30; this.Frame.ChartBorder.Left = 5; this.Frame.ChartBorder.Bottom = 20; this.Frame.Canvas = this.Canvas; this.ChartSplashPaint.Frame = this.Frame; this.CreateMainChart(); } this.SetMainDataConotrl = function (dataControl) { if (!dataControl) return; this.MainDataControl = dataControl; this.ChartPaint = []; //图形 this.CreateMainChart(); this.Draw(); this.RequestData(); } //创建主数据画法 this.CreateMainChart = function () { if (!this.MainDataControl) return; for (let i in this.MainDataControl.DataType) { let item = this.MainDataControl.DataType[i]; if (item.Type == "PIE") { var chartItem = new ChartPie(); chartItem.Canvas = this.Canvas; chartItem.ChartBorder = this.Frame.ChartBorder; chartItem.ChartFrame = this.Frame; chartItem.Name = item.Name; this.ChartPaint.push(chartItem); } else if (item.Type == 'CIRCLE') { var chartItem = new ChartCircle(); chartItem.Canvas = this.Canvas; chartItem.ChartBorder = this.Frame.ChartBorder; chartItem.ChartFrame = this.Frame; chartItem.Name = item.Name; this.ChartPaint.push(chartItem); } else if (item.Type == 'RADAR') //雷达图 { var chartItem = new ChartRadar(); chartItem.Canvas = this.Canvas; chartItem.ChartBorder = this.Frame.ChartBorder; chartItem.ChartFrame = this.Frame; chartItem.Name = item.Name; if (item.StartAngle) chartItem.StartAngle = item.StartAngle; if (item.TitleFont) chartItem.TitleFont = item.TitleFont; this.ChartPaint.push(chartItem); } } // this.TitlePaint[0]=new DynamicKLineTitlePainting(); // this.TitlePaint[0].Frame=this.Frame.SubFrame[0].Frame; // this.TitlePaint[0].Canvas=this.Canvas; } this.RequestData = function () { if (!this.MainDataControl) return; this.MainDataControl.JSChartContainer = this; this.MainDataControl.RequestData(); } this.UpdateMainData = function (dataControl) { for (let i in dataControl.Data) { let itemData = new ChartData(); itemData.Data = dataControl.Data[i]; this.ChartPaint[i].Data = itemData; } this.Frame.SetSizeChage(true); this.Draw(); } } //地图 function MapChartContainer(uielement) { this.newMethod = JSChartContainer; //派生 this.newMethod(uielement); delete this.newMethod; this.MainDataControl; //主数据类(对外的接口类) //鼠标移动 this.OnMouseMove = function (x, y, e) { } //创建 this.Create = function () { this.UIElement.JSChartContainer = this; //创建等待提示 this.ChartSplashPaint = new ChartSplashPaint(); this.ChartSplashPaint.Canvas = this.Canvas; //创建框架容器 this.Frame = new NoneFrame(); this.Frame.ChartBorder = new ChartBorder(); this.Frame.ChartBorder.UIElement = this.UIElement; this.Frame.ChartBorder.Top = 30; this.Frame.ChartBorder.Left = 5; this.Frame.ChartBorder.Bottom = 20; this.Frame.Canvas = this.Canvas; this.ChartSplashPaint.Frame = this.Frame; this.CreateMainChart(); } this.SetMainDataConotrl = function (dataControl) { if (!dataControl) return; this.MainDataControl = dataControl; this.ChartPaint = []; //图形 this.CreateMainChart(); this.Draw(); this.RequestData(); } //创建主数据画法 this.CreateMainChart = function () { if (!this.MainDataControl) return; let chartItem = new ChartChinaMap(); chartItem.Canvas = this.Canvas; chartItem.ChartBorder = this.Frame.ChartBorder; chartItem.ChartFrame = this.Frame; chartItem.Name = this.MainDataControl.DataType[0].Name; if (this.Radius) chartItem.Radius = this.Radius; this.ChartPaint.push(chartItem); // this.TitlePaint[0]=new DynamicKLineTitlePainting(); // this.TitlePaint[0].Frame=this.Frame.SubFrame[0].Frame; // this.TitlePaint[0].Canvas=this.Canvas; } this.RequestData = function () { if (!this.MainDataControl) return; this.MainDataControl.JSChartContainer = this; this.MainDataControl.RequestData(); } this.UpdateMainData = function (dataControl) { this.ChartPaint[0].Data = dataControl.Data[0]; this.Frame.SetSizeChage(true); this.Draw(); } } var HQ_DATA_TYPE = { KLINE_ID: 0, //K线 MINUTE_ID: 2, //当日走势图 HISTORY_MINUTE_ID: 3,//历史分钟走势图 MULTIDAY_MINUTE_ID: 4,//多日走势图 }; function APIScriptIndex(name, script, args, option) //后台执行指标 { this.newMethod = ScriptIndex; //派生 this.newMethod(name, script, args, option); delete this.newMethod; this.ApiUrl; //指标执行api地址 this.HQDataType; if (option.API) { if (option.API.Url) this.ApiUrl = option.API.Url; if (option.API.Name) this.Name = this.ID = option.API.Name; if (option.API.ID) this.ID = option.API.ID; } this.ExecuteScript = function (hqChart, windowIndex, hisData) { JSConsole.Chart.Log('[APIScriptIndex::ExecuteScript] name, Arguments ', this.Name, this.Arguments); //数据类型 let hqDataType = HQ_DATA_TYPE.KLINE_ID; //默认K线 if (hqChart.ClassName === 'MinuteChartContainer' || hqChart.ClassName === 'MinuteChartHScreenContainer') { if (hqChart.DayCount > 1) hqDataType = HQ_DATA_TYPE.MULTIDAY_MINUTE_ID; //多日分钟 else hqDataType = HQ_DATA_TYPE.MINUTE_ID; //分钟数据 } else if (hqChart.ClassName === 'HistoryMinuteChartContainer') { hqDataType = HQ_DATA_TYPE.HISTORY_MINUTE_ID; //历史分钟 } var args = []; if (this.Arguments) { for (var i in this.Arguments) { var item = this.Arguments[i]; args.push({ name: item.Name, value: item.Value }); } } var requestCount = hqChart.GetRequestDataCount(); var self = this; var postData = { indexname: this.ID, symbol: hqChart.Symbol, script: this.Script, args: args, period: hqChart.Period, right: hqChart.Right, maxdatacount: requestCount.MaxRequestDataCount, maxminutedaycount: requestCount.MaxRequestMinuteDayCount, hqdatatype: hqDataType }; if (hqDataType == HQ_DATA_TYPE.MULTIDAY_MINUTE_ID || hqDataType == HQ_DATA_TYPE.MINUTE_ID) postData.daycount = hqChart.DayCount; this.HQDataType = hqDataType; if (hqChart.NetworkFilter) { var obj = { Name: 'APIScriptIndex::ExecuteScript', //类名:: Explain: '指标计算', Request: { Url: self.ApiUrl, Type: 'POST', Data: postData }, Self: this, HQChart: hqChart, PreventDefault: false }; hqChart.NetworkFilter(obj, function (data) { self.RecvAPIData(data, hqChart, windowIndex, hisData); }); if (obj.PreventDefault == true) return; //已被上层替换,不调用默认的网络请求 } wx.request({ url: self.ApiUrl, data: postData, method: 'POST', dataType: "json", async: true, success: function (recvData) { self.RecvAPIData(recvData, hqChart, windowIndex, hisData); }, error: function (request) { self.RecvError(request); } }); } this.RecvAPIData = function (recvData, hqChart, windowIndex, hisData) { var data=recvData.data; JSConsole.Chart.Log('[APIScriptIndex::RecvAPIData] recv data ', this.Name, data); if (data.code != 0) return; if (data.outdata && data.outdata.name) this.Name = data.outdata.name; if (data.outdata.args) //外部修改显示参数 { this.Arguments = []; for (var i in data.outdata.args) { var item = data.outdata.args[i]; this.Arguments.push({ Name: item.name, Value: item.value }); } } if (this.HQDataType == HQ_DATA_TYPE.KLINE_ID) { this.OutVar = this.FittingData(data.outdata, hqChart); JSConsole.Chart.Log('[APIScriptIndex::RecvAPIData] conver to OutVar ', this.OutVar); } else { this.OutVar = this.FittingMinuteData(data.outdata, hqChart); //走势图数据 } this.BindData(hqChart, windowIndex, hisData); if (this.IsLocked == false) //不上锁 { hqChart.Frame.SubFrame[windowIndex].Frame.SetLock(null); } else //上锁 { let lockData = { IsLocked: true, Callback: this.LockCallback, IndexName: this.Name, ID: this.LockID, BG: this.LockBG, Text: this.LockText, TextColor: this.LockTextColor, Font: this.LockFont, Count: this.LockCount, MinWidth: this.LockMinWidth }; hqChart.Frame.SubFrame[windowIndex].Frame.SetLock(lockData); } hqChart.UpdataDataoffset(); //更新数据偏移 hqChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 hqChart.Draw(); if (hqChart.GetIndexEvent) { var event = hqChart.GetIndexEvent(); //指标计算完成回调 if (event) { var data = { OutVar: this.OutVar, WindowIndex: windowIndex, Name: this.Name, Arguments: this.Arguments, HistoryData: hisData, Stock: { Symbol: hqChart.Symbol, Name: hqChart.Name } }; event.Callback(event, data, this); } } } this.FittingData = function (jsonData, hqChart) { var outVar = jsonData.outvar; var date = jsonData.date; var time = jsonData.time; var kdata = hqChart.ChartPaint[0].Data; //把数据拟合到kdata上 var result = []; for (var i in outVar) { var item = outVar[i]; var indexData = []; var outVarItem = { Name: item.name, Type: item.type }; if (item.color) outVarItem.Color = item.color; if (item.data) { outVarItem.Data = this.FittingArray(item.data, date, time, hqChart); if (item.color) outVarItem.Color = item.color; if (item.linewidth >= 1) outVarItem.LineWidth = item.linewidth; if (item.isshow == false) outVarItem.IsShow = false; if (item.isexdata == true) outVarItem.IsExData = true; result.push(outVarItem); } else if (item.Draw) { var draw = item.Draw; var drawItem = {}; if (draw.DrawType == 'DRAWICON') //图标 { drawItem.Icon = draw.Icon; drawItem.Name = draw.Name; drawItem.DrawType = draw.DrawType; drawItem.DrawData = this.FittingArray(draw.DrawData, date, time, hqChart); outVarItem.Draw = drawItem; result.push(outVarItem); } else if (draw.DrawType == 'DRAWTEXT') //文本 { drawItem.Text = draw.Text; drawItem.Name = draw.Name; drawItem.DrawType = draw.DrawType; drawItem.DrawData = this.FittingArray(draw.DrawData, date, time, hqChart); outVarItem.Draw = drawItem; result.push(outVarItem); } else if (draw.DrawType == 'STICKLINE') //柱子 { drawItem.Name = draw.Name; drawItem.Type = draw.Type; drawItem.Width = draw.Width; drawItem.DrawType = draw.DrawType; drawItem.DrawData = this.FittingArray(draw.DrawData, date, time, hqChart, 1); outVarItem.Draw = drawItem; result.push(outVarItem); } else if (draw.DrawType == 'MULTI_LINE') { drawItem.Text = draw.Text; drawItem.Name = draw.Name; drawItem.DrawType = draw.DrawType; drawItem.DrawData = this.FittingMultiLine(draw.DrawData, date, time, hqChart); outVarItem.Draw = drawItem; if (draw.LineDash) drawItem.LineDash=draw.LineDash; //if (draw.Arrow) drawItem.Arrow=draw.Arrow; if (IFrameSplitOperator.IsNumber(draw.LineWidth)) drawItem.LineWidth=draw.LineWidth; result.push(outVarItem); } else if (draw.DrawType == 'MULTI_BAR') { drawItem.Text = draw.Text; drawItem.Name = draw.Name; drawItem.DrawType = draw.DrawType; drawItem.DrawData = this.FittingMultiLine(draw.DrawData, date, time, hqChart); outVarItem.Draw = drawItem; result.push(outVarItem); } else if (draw.DrawType == 'MULTI_TEXT') { drawItem.Text = draw.Text; drawItem.Name = draw.Name; drawItem.DrawType = draw.DrawType; drawItem.DrawData = this.FittingMultiText(draw.DrawData, date, time, hqChart); this.GetKLineData(drawItem.DrawData, hqChart); outVarItem.Draw = drawItem; result.push(outVarItem); } else if (draw.DrawType=="MULTI_HTMLDOM") //外部自己创建dom { drawItem.Text=draw.Text; drawItem.Name=draw.Name; drawItem.DrawType=draw.DrawType; drawItem.Callback=draw.Callback; drawItem.DrawData=this.FittingMultiText(draw.DrawData,date,time,hqChart); this.GetKLineData(drawItem.DrawData, hqChart); outVarItem.Draw=drawItem; result.push(outVarItem); } else if (draw.DrawType=="KLINE_BG") { drawItem.Name=draw.Name; drawItem.DrawType=draw.DrawType; drawItem.DrawData={ Color:draw.Color, Angle:draw.Angle }; drawItem.DrawData.Data=this.FittingKLineBG(draw.DrawData, hqChart); outVarItem.Draw=drawItem; outVarItem.Name=draw.DrawType; result.push(outVarItem); } } } return result; } // h, high, low l. this.GetKLineData=function(data,hqChart) { if (!data) return; if (!Array.isArray(data)) return; var kData=hqChart.ChartPaint[0].Data; //K线 for(var i in data) { var item=data[i]; if (!IFrameSplitOperator.IsString(item.Value)) continue; if(!IFrameSplitOperator.IsNumber(item.Index)) continue; if (item.Index<0 || item.Index>=kData.Data.length) continue; var valueName=item.Value.toUpperCase(); var kItem=kData.Data[item.Index]; switch(valueName) { case "HIGH": case "H": item.Value=kItem.High; break; case "L": case "LOW": item.Value=kItem.Low; break; } } } this.FittingKLineBG=function(data, hqChart) { var kData=hqChart.ChartPaint[0].Data; //K线 var result=[]; if (ChartData.IsDayPeriod(hqChart.Period,true)) //日线 { var bFill=false; for(var i=0,j=0;i=data.length) { ++i; continue; } var dataItem=data[j]; if (dataItem.DatekItem.Date) { ++i; } else { bFill=true; result[i]=1; ++j; ++i; } } if (bFill) return result; } else if (ChartData.IsMinutePeriod(hqChart.Period,true)) //分钟线 { var bFill=false; for(var i=0,j=0;i=data.length) { ++i; continue; } var dataItem=data[j]; if (dataItem.DatekItem.Date || (dataItem.Date==kItem.Date && dataItem.Time>kItem.Time)) { ++i; } else { bFill=true; result[i]=1; ++j; ++i; } } if (bFill) return result; } return null; } this.FittingArray = function (sourceData, date, time, hqChart, arrayType) //arrayType 0=单值数组 1=结构体 { var kdata = hqChart.ChartPaint[0].Data; //K线 var arySingleData = []; for (var i in sourceData) { var value = sourceData[i]; var indexItem = new SingleData(); //单列指标数据 indexItem.Date = date[i]; if (time && i < time.length) indexItem.Time = time[i]; indexItem.Value = value; arySingleData.push(indexItem); } var aryFittingData; if (ChartData.IsDayPeriod(hqChart.Period,true)) aryFittingData = kdata.GetFittingData(arySingleData); //数据和主图K线拟合 else aryFittingData = kdata.GetMinuteFittingData(arySingleData); //数据和主图K线拟合 var bindData = new ChartData(); bindData.Data = aryFittingData; var result; if (arrayType == 1) result = bindData.GetObject(); else result = bindData.GetValue(); return result; } this.FittingMultiLine = function (sourceData, date, time, hqChart) { var kdata = hqChart.ChartPaint[0].Data; //K线 if (ChartData.IsDayPeriod(hqChart.Period, true)) //日线 { var aryPoint = []; for (var i in sourceData) { var item = sourceData[i]; for (var j in item.Point) { var point = item.Point[j]; aryPoint.push(point); } } aryPoint.sort(function (a, b) { return a.Date - b.Date; }); kdata.GetDateIndex(aryPoint); return sourceData; } else if (ChartData.IsMinutePeriod(hqChart.Period, true)) //分钟线 { var aryPoint = []; for (var i in sourceData) { var item = sourceData[i]; for (var j in item.Point) { var point = item.Point[j]; aryPoint.push(point); } } aryPoint.sort(function (a, b) { if (a.Date == b.Date) return a.Time - b.Time; return a.Date - b.Date; }); kdata.GetDateTimeIndex(aryPoint); return sourceData; } return null; } this.FittingMultiText = function (sourceData, date, time, hqChart) { var kdata = hqChart.ChartPaint[0].Data; //K线 if (ChartData.IsDayPeriod(hqChart.Period, true)) //日线 { sourceData.sort(function (a, b) { return a.Date - b.Date; }); kdata.GetDateIndex(sourceData); return sourceData; } else if (ChartData.IsMinutePeriod(hqChart.Period, true)) //分钟线 { sourceData.sort(function (a, b) { if (a.Date == b.Date) return a.Time - b.Time; return a.Date - b.Date; } ); kdata.GetDateTimeIndex(sourceData); return sourceData; } return null; } } //市场多空 function MarketLongShortIndex() { this.newMethod = BaseIndex; //派生 this.newMethod('市场多空'); delete this.newMethod; this.Index = new Array( new IndexInfo("多空指标", null), new IndexInfo("多头区域", null), new IndexInfo("空头区域", null) ); this.Index[0].LineColor = g_JSChartResource.Index.LineColor[0]; this.Index[1].LineColor = g_JSChartResource.UpBarColor; this.Index[2].LineColor = g_JSChartResource.DownBarColor; this.LongShortData; //多空数据 this.Create = function (hqChart, windowIndex) { for (var i in this.Index) { var paint = null; if (i == 0) paint = new ChartLine(); else paint = new ChartStraightLine(); paint.Color = this.Index[i].LineColor; paint.Canvas = hqChart.Canvas; paint.Name = this.Name + "-" + i.toString(); paint.ChartBorder = hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; paint.ChartFrame = hqChart.Frame.SubFrame[windowIndex].Frame; hqChart.ChartPaint.push(paint); } } //请求数据 this.RequestData = function (hqChart, windowIndex, hisData) { var self = this; var param = { HQChart: hqChart, WindowIndex: windowIndex, HistoryData: hisData }; this.LongShortData = []; if (param.HQChart.Period > 0) //周期数据 { this.NotSupport(param.HQChart, param.WindowIndex, "不支持周期切换"); param.HQChart.Draw(); return false; } //请求数据 wx.request({ url: g_JSChartResource.Index.MarketLongShortApiUrl, data: { }, method: 'POST', dataType: "json", async: true, success: function (recvData) { self.RecvData(recvData, param); } }); return true; } this.RecvData = function (recvData, param) { if (recvData.data.data.length <= 0) return; var aryData = new Array(); for (var i in recvData.data.data) { var item = recvData.data.data[i]; var indexData = new SingleData(); indexData.Date = item[0]; indexData.Value = item[1]; aryData.push(indexData); } var aryFittingData = param.HistoryData.GetFittingData(aryData); var bindData = new ChartData(); bindData.Data = aryFittingData; bindData.Period = param.HQChart.Period; //周期 bindData.Right = param.HQChart.Right; //复权 this.LongShortData = bindData.GetValue(); this.BindData(param.HQChart, param.WindowIndex, param.HistoryData); param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); } this.BindData = function (hqChart, windowIndex, hisData) { var paint = hqChart.GetChartPaint(windowIndex); if (paint.length != this.Index.length) return false; //paint[0].Data.Data=SWLData; paint[0].Data.Data = this.LongShortData; paint[0].NotSupportMessage = null; paint[1].Data.Data[0] = 8; paint[2].Data.Data[0] = 1; //指定[0,9] hqChart.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin = { Max: 9, Min: 0, Count: 3 }; var titleIndex = windowIndex + 1; for (var i in paint) { hqChart.TitlePaint[titleIndex].Data[i] = new DynamicTitleData(paint[i].Data, this.Index[i].Name, this.Index[i].LineColor); if (i > 0) hqChart.TitlePaint[titleIndex].Data[i].DataType = "StraightLine"; } hqChart.TitlePaint[titleIndex].Title = this.FormatIndexTitle(); if (hqChart.UpdateUICallback) hqChart.UpdateUICallback('MarketLongShortIndex', paint, { WindowIndex: windowIndex, HistoryData: hisData }); //通知上层回调 return true; } } //市场择时 function MarketTimingIndex() { this.newMethod = BaseIndex; //派生 this.newMethod('市场择时'); delete this.newMethod; this.Index = new Array( new IndexInfo("因子择时", null) ); this.TimingData; //择时数据 this.TitleColor = g_JSChartResource.FrameSplitTextColor this.Create = function (hqChart, windowIndex) { for (var i in this.Index) { var paint = new ChartMACD(); paint.Canvas = hqChart.Canvas; paint.Name = this.Name + "-" + i.toString(); paint.ChartBorder = hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; paint.ChartFrame = hqChart.Frame.SubFrame[windowIndex].Frame; hqChart.ChartPaint.push(paint); } } //请求数据 this.RequestData = function (hqChart, windowIndex, hisData) { var self = this; var param = { HQChart: hqChart, WindowIndex: windowIndex, HistoryData: hisData }; this.LongShortData = []; if (param.HQChart.Period > 0) //周期数据 { this.NotSupport(param.HQChart, param.WindowIndex, "不支持周期切换"); param.HQChart.Draw(); return false; } //请求数据 wx.request({ url: g_JSChartResource.Index.MarketLongShortApiUrl, data: { }, method: 'POST', dataType: "json", async: true, success: function (recvData) { self.RecvData(recvData, param); } }); return true; } this.RecvData = function (recvData, param) { if (recvData.data.data.length <= 0) return; var aryData = new Array(); for (var i in recvData.data.data) { var item = recvData.data.data[i]; var indexData = new SingleData(); indexData.Date = item[0]; indexData.Value = item[2]; aryData.push(indexData); } var aryFittingData = param.HistoryData.GetFittingData(aryData); var bindData = new ChartData(); bindData.Data = aryFittingData; bindData.Period = param.HQChart.Period; //周期 bindData.Right = param.HQChart.Right; //复权 this.TimingData = bindData.GetValue(); this.BindData(param.HQChart, param.WindowIndex, param.HistoryData); param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); } this.BindData = function (hqChart, windowIndex, hisData) { var paint = hqChart.GetChartPaint(windowIndex); if (paint.length != this.Index.length) return false; //paint[0].Data.Data=SWLData; paint[0].Data.Data = this.TimingData; paint[0].NotSupportMessage = null; var titleIndex = windowIndex + 1; for (var i in paint) { hqChart.TitlePaint[titleIndex].Data[i] = new DynamicTitleData(paint[i].Data, this.Index[i].Name, this.TitleColor); hqChart.TitlePaint[titleIndex].Data[i].StringFormat = STRING_FORMAT_TYPE.THOUSANDS; hqChart.TitlePaint[titleIndex].Data[i].FloatPrecision = 0; } hqChart.TitlePaint[titleIndex].Title = this.FormatIndexTitle(); if (hqChart.UpdateUICallback) hqChart.UpdateUICallback('MarketTimingIndex', paint, { WindowIndex: windowIndex, HistoryData: hisData }); //通知上层回调 return true; } } //市场关注度 function MarketAttentionIndex() { this.newMethod = BaseIndex; //派生 this.newMethod('市场关注度'); delete this.newMethod; this.Index = new Array( new IndexInfo("市场关注度指数", null) ); this.Data; //关注度数据 this.TitleColor = g_JSChartResource.FrameSplitTextColor; this.ApiUrl = g_JSChartResource.Index.MarketAttentionApiUrl; this.Create = function (hqChart, windowIndex) { for (var i in this.Index) { var paint = new ChartBar(); //柱子 paint.Canvas = hqChart.Canvas; paint.Name = this.Name + "-" + i.toString(); paint.ChartBorder = hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; paint.ChartFrame = hqChart.Frame.SubFrame[windowIndex].Frame; paint.UpBarColor = paint.DownBarColor = 'rgb(243,152,0)'; hqChart.ChartPaint.push(paint); } } //调整框架 this.SetFrame = function (hqChart, windowIndex, hisData) { hqChart.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin = { Max: 6, Min: 0, Count: 3 }; } //请求数据 this.RequestData = function (hqChart, windowIndex, hisData) { var self = this; var param = { HQChart: hqChart, WindowIndex: windowIndex, HistoryData: hisData }; this.Data = []; if (param.HQChart.Period > 0) //周期数据 { this.NotSupport(param.HQChart, param.WindowIndex, "不支持周期切换"); param.HQChart.Draw(); return false; } //请求数据 wx.request({ url: this.ApiUrl, data: { "symbol": param.HQChart.Symbol, "startdate": 20100101, }, method: 'POST', dataType: "json", success: function (recvData) { self.RecvData(recvData.data, param); } }); return true; } this.RecvData = function (recvData, param) { if (recvData.date.length < 0) return; var aryData = new Array(); for (var i in recvData.date) { var indexData = new SingleData(); indexData.Date = recvData.date[i]; indexData.Value = recvData.value[i]; aryData.push(indexData); } var aryFittingData = param.HistoryData.GetFittingData(aryData); var bindData = new ChartData(); bindData.Data = aryFittingData; bindData.Period = param.HQChart.Period; //周期 bindData.Right = param.HQChart.Right; //复权 this.Data = bindData.GetValue(); this.BindData(param.HQChart, param.WindowIndex, param.HistoryData); this.SetFrame(param.HQChart, param.WindowIndex, param.HistoryData); param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); // if (typeof (this.UpdateUICallback) == 'function') this.UpdateUICallback('RecvHistoryData', this); } this.BindData = function (hqChart, windowIndex, hisData) { var paint = hqChart.GetChartPaint(windowIndex); if (paint.length != this.Index.length) return false; //paint[0].Data.Data=SWLData; paint[0].Data.Data = this.Data; paint[0].NotSupportMessage = null; var titleIndex = windowIndex + 1; for (var i in paint) { hqChart.TitlePaint[titleIndex].Data[i] = new DynamicTitleData(paint[i].Data, this.Index[i].Name, this.TitleColor); hqChart.TitlePaint[titleIndex].Data[i].StringFormat = STRING_FORMAT_TYPE.THOUSANDS; hqChart.TitlePaint[titleIndex].Data[i].FloatPrecision = 0; } hqChart.TitlePaint[titleIndex].Title = this.FormatIndexTitle(); return true; } } /* 行业,指数热度 */ function MarketHeatIndex() { this.newMethod = BaseIndex; //派生 this.newMethod('指数/行业热度'); delete this.newMethod; this.Index = new Array( new IndexInfo("热度指数", 5), new IndexInfo('MA', 10), new IndexInfo('MA', null) ); this.Data; //关注度数据 this.ApiUrl = g_JSChartResource.Index.MarketHeatApiUrl; this.Index[0].LineColor = g_JSChartResource.FrameSplitTextColor; this.Index[1].LineColor = g_JSChartResource.Index.LineColor[0]; this.Index[2].LineColor = g_JSChartResource.Index.LineColor[1]; this.Create = function (hqChart, windowIndex) { for (var i in this.Index) { var paint = null; if (i == 0) { paint = new ChartMACD(); //柱子 } else { paint = new ChartLine(); paint.Color = this.Index[i].LineColor; } paint.Canvas = hqChart.Canvas; paint.Name = this.Name + "-" + i.toString(); paint.ChartBorder = hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; paint.ChartFrame = hqChart.Frame.SubFrame[windowIndex].Frame; hqChart.ChartPaint.push(paint); } } //请求数据 this.RequestData = function (hqChart, windowIndex, hisData) { var self = this; var param = { HQChart: hqChart, WindowIndex: windowIndex, HistoryData: hisData }; this.Data = []; if (param.HQChart.Period > 0) //周期数据 { this.NotSupport(param.HQChart, param.WindowIndex, "不支持周期切换"); param.HQChart.Draw(); return false; } //请求数据 wx.request({ url: this.ApiUrl, data: { "symbol": param.HQChart.Symbol, "startdate": 20100101, }, method: 'POST', dataType: "json", success: function (recvData) { self.RecvData(recvData.data, param); } }); return true; } this.RecvData = function (recvData, param) { if (recvData.date.length < 0) return; var aryData = new Array(); for (var i in recvData.date) { var indexData = new SingleData(); indexData.Date = recvData.date[i]; indexData.Value = recvData.value[i]; aryData.push(indexData); } var aryFittingData = param.HistoryData.GetFittingData(aryData); var bindData = new ChartData(); bindData.Data = aryFittingData; bindData.Period = param.HQChart.Period; //周期 bindData.Right = param.HQChart.Right; //复权 this.Data = bindData.GetValue(); this.BindData(param.HQChart, param.WindowIndex, param.HistoryData); param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); } this.BindData = function (hqChart, windowIndex, hisData) { var paint = hqChart.GetChartPaint(windowIndex); if (paint.length != this.Index.length) return false; paint[0].Data.Data = this.Data; paint[0].NotSupportMessage = null; var MA = HQIndexFormula.MA(this.Data, this.Index[0].Param); paint[1].Data.Data = MA; var MA2 = HQIndexFormula.MA(this.Data, this.Index[1].Param); paint[2].Data.Data = MA2; var titleIndex = windowIndex + 1; for (var i in paint) { var name = ""; //显示的名字特殊处理 if (i == 0) name = hqChart.Name + this.Index[i].Name; else name = "MA" + this.Index[i - 1].Param; hqChart.TitlePaint[titleIndex].Data[i] = new DynamicTitleData(paint[i].Data, name, this.Index[i].LineColor); hqChart.TitlePaint[titleIndex].Data[i].StringFormat = STRING_FORMAT_TYPE.DEFAULT; hqChart.TitlePaint[titleIndex].Data[i].FloatPrecision = 2; } hqChart.TitlePaint[titleIndex].Title = this.FormatIndexTitle(); return true; } } //自定义指数热度 function CustonIndexHeatIndex() { this.newMethod = BaseIndex; //派生 this.newMethod('Market-Heat'); delete this.newMethod; this.Index = new Array( new IndexInfo('区域', 3), new IndexInfo("热度指数", 10), new IndexInfo('MA', 5), new IndexInfo('MA', 10) ); this.Data; //热度数据 this.ApiUrl = g_JSChartResource.Index.CustomIndexHeatApiUrl; this.Index[1].LineColor = g_JSChartResource.Index.LineColor[1]; this.Index[2].LineColor = g_JSChartResource.Index.LineColor[2]; this.Index[3].LineColor = g_JSChartResource.Index.LineColor[3]; this.Create = function (hqChart, windowIndex) { for (var i in this.Index) { var paint = null; if (i == 0) { paint = new ChartStraightArea(); } else { paint = new ChartLine(); paint.Color = this.Index[i].LineColor; } paint.Canvas = hqChart.Canvas; paint.Name = this.Name + "-" + i.toString(); paint.ChartBorder = hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; paint.ChartFrame = hqChart.Frame.SubFrame[windowIndex].Frame; hqChart.ChartPaint.push(paint); } } //请求数据 this.RequestData = function (hqChart, windowIndex, hisData) { var self = this; var param = { HQChart: hqChart, WindowIndex: windowIndex, HistoryData: hisData }; this.Data = []; if (param.HQChart.Period > 0) //周期数据 { this.NotSupport(param.HQChart, param.WindowIndex, "不支持周期切换"); param.HQChart.Draw(); return false; } //请求数据 wx.request({ url: this.ApiUrl, data: { "stock": param.HQChart.CustomStock, "date": { "startdate": param.HQChart.QueryDate.Start, "enddate": param.HQChart.QueryDate.End }, "day": [this.Index[0].Param, this.Index[1].Param], }, method: 'POST', dataType: "json", success: function (recvData) { self.RecvData(recvData, param); } }); return true; } this.RecvData = function (recvData, param) { let data = recvData.data; if (data.data == null || data.data.length < 0) return; //JSConsole.Chart.Log(recvData.data); let aryData = new Array(); for (let i in data.data) { let item = data.data[i]; let indexData = new SingleData(); indexData.Date = item[0]; indexData.Value = item[1]; aryData.push(indexData); } var aryFittingData = param.HistoryData.GetFittingData(aryData); var bindData = new ChartData(); bindData.Data = aryFittingData; bindData.Period = param.HQChart.Period; //周期 bindData.Right = param.HQChart.Right; //复权 this.Data = bindData.GetValue(); this.BindData(param.HQChart, param.WindowIndex, param.HistoryData); param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); } this.BindData = function (hqChart, windowIndex, hisData) { let paint = hqChart.GetChartPaint(windowIndex); if (paint.length != this.Index.length) return false; paint[0].NotSupportMessage = null; paint[0].Data.Data = [ { Value: 0, Value2: 0.2, Color: 'rgb(46,139,87)', Title: '较差区', TitleColor: 'rgb(245,255 ,250)' }, { Value: 0.19, Value2: 0.4, Color: 'rgb(255,140,0)', Title: '变热区', TitleColor: 'rgb(245,255 ,250)' }, { Value: 0.39, Value2: 0.8, Color: 'rgb(255,106,106)', Title: '较好区', TitleColor: 'rgb(245,255 ,250)' }, { Value: 0.79, Value2: 1, Color: 'rgb(255,69,0)', Title: '过热区', TitleColor: 'rgb(245,255 ,250)' } ]; paint[1].Data.Data = this.Data; let MA = HQIndexFormula.MA(this.Data, this.Index[2].Param); paint[2].Data.Data = MA; let MA2 = HQIndexFormula.MA(this.Data, this.Index[3].Param); paint[3].Data.Data = MA2; //指定框架最大最小[0,1] hqChart.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin = { Max: 1, Min: 0, Count: 3 }; let titleIndex = windowIndex + 1; for (let i = 1; i < paint.length; ++i) { let name = this.Index[i].Name; //显示的名字特殊处理 if (name == 'MA') name = "MA" + this.Index[i].Param; hqChart.TitlePaint[titleIndex].Data[i] = new DynamicTitleData(paint[i].Data, name, this.Index[i].LineColor); hqChart.TitlePaint[titleIndex].Data[i].StringFormat = STRING_FORMAT_TYPE.DEFAULT; hqChart.TitlePaint[titleIndex].Data[i].FloatPrecision = 2; } hqChart.TitlePaint[titleIndex].Title = '热度' + '(' + this.Index[0].Param + ',' + this.Index[1].Param + ',' + this.Index[2].Param + ',' + this.Index[3].Param + ')'; return true; } } /* 本福特系数(财务粉饰) */ function BenfordIndex() { this.newMethod = BaseIndex; //派生 this.newMethod('财务风险'); delete this.newMethod; this.Index = new Array( new IndexInfo('区域', null), new IndexInfo("系数", null), ); this.Data; //财务数据 this.ApiUrl = g_JSChartResource.Index.StockHistoryDayApiUrl; this.Index[0].LineColor = g_JSChartResource.Index.LineColor[0]; this.Index[1].LineColor = 'rgb(105,105,105)'; this.Create = function (hqChart, windowIndex) { for (var i in this.Index) { var paint = null; if (i == 0) paint = new ChartStraightArea(); else if (i == 1) paint = new ChartLineMultiData(); if (paint) { paint.Color = this.Index[i].LineColor; paint.Canvas = hqChart.Canvas; paint.Name = this.Name + "-" + i.toString(); paint.ChartBorder = hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; paint.ChartFrame = hqChart.Frame.SubFrame[windowIndex].Frame; hqChart.ChartPaint.push(paint); } } } //请求数据 this.RequestData = function (hqChart, windowIndex, hisData) { var self = this; var param = { HQChart: hqChart, WindowIndex: windowIndex, HistoryData: hisData }; this.Data = []; if (param.HQChart.Period != 2) //周期数据 { this.NotSupport(param.HQChart, param.WindowIndex, "只支持月线"); param.HQChart.Draw(); return false; } var aryField = ["finance.benford", "announcement2.quarter", "announcement1.quarter", "announcement3.quarter", "announcement4.quarter"]; var aryCondition = [ { item: ["date", "int32", "gte", "20130101"] }, { item: ["announcement1.year", "int32", "gte", 0, "announcement2.year", "int32", "gte", 0, "announcement3.year", "int32", "gte", 0, "announcement4.year", "int32", "gte", 0, "or"] } ]; //请求数据 wx.request({ url: this.ApiUrl, data: { "symbol": [param.HQChart.Symbol], "field": aryField, "condition": aryCondition }, method: 'POST', dataType: "json", success: function (recvData) { self.RecvData(recvData, param); } }); return true; } this.JsonDataToMapSingleData = function (recvData) { var stockData = recvData.stock[0].stockday; var mapData = new Map(); for (var i in stockData) { var item = stockData[i]; var indexData = new SingleData(); indexData.Date = item.date; indexData.Value = new Array(); if (item.finance1 != null && item.announcement1 != null) { let year = item.announcement1.year; let quarter = item.announcement1.quarter; let value = item.finance1.benford; indexData.Value.push({ Year: year, Quarter: quarter, Value: value }); } if (item.finance2 != null && item.announcement2 != null) { let year = item.announcement2.year; let quarter = item.announcement2.quarter; let value = item.finance2.benford; indexData.Value.push({ Year: year, Quarter: quarter, Value: value }); } if (item.finance3 != null && item.announcement3 != null) { let year = item.announcement3.year; let quarter = item.announcement3.quarter; let value = item.finance3.benford; indexData.Value.push({ Year: year, Quarter: quarter, Value: value }); } if (item.finance4 != null && item.announcement4 != null) { let year = item.announcement4.year; let quarter = item.announcement4.quarter; let value = item.finance4.benford; indexData.Value.push({ Year: year, Quarter: quarter, Value: value }); } mapData.set(indexData.Date, indexData); } var aryData = new Array(); for (var item of mapData) { aryData.push(item[1]); } return aryData; } this.RecvData = function (recvData, param) { JSConsole.Chart.Log(recvData); if (recvData.data.stock == null || recvData.data.stock.length <= 0) return; var aryData = this.JsonDataToMapSingleData(recvData.data); var aryFittingData = param.HistoryData.GetFittingMonthData(aryData); var bindData = new ChartData(); bindData.Data = aryFittingData; bindData.Period = param.HQChart.Period; //周期 bindData.Right = param.HQChart.Right; //复权 this.Data = bindData.GetValue(); this.BindData(param.HQChart, param.WindowIndex, param.HistoryData); param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); } this.BindData = function (hqChart, windowIndex, hisData) { var paint = hqChart.GetChartPaint(windowIndex); if (paint.length != this.Index.length) return false; paint[0].NotSupportMessage = null; paint[0].Data.Data = [ // { Value: 0, Value2: 0.2, Color: 'rgb(50,205,50)', Title: '安全区', TitleColor: 'rgb(245,255 ,250)' }, // { Value: 0.2, Value2: 0.4, Color: 'rgb(255,140,0)', Title: '预警区', TitleColor: 'rgb(245,255 ,250)' }, // { Value: 0.4, Value2: 1, Color: 'rgb(255,106,106)', Title: '警示区', TitleColor: 'rgb(245,255 ,250)' } { Value: 0, Value2: 0.2, Color: 'rgb(219,255,193)', Title: '安全区', TitleColor: 'rgb(66,192,99)' }, { Value: 0.2, Value2: 0.4, Color: 'rgb(255,228,170)', Title: '预警区', TitleColor: 'rgb(255,124,3)' }, { Value: 0.4, Value2: 1, Color: 'rgb(254,219,212)', Title: '警示区', TitleColor: 'rgb(255,0,0)' } ]; paint[1].Data.Data = this.Data; //指定框架最大最小[0,1] hqChart.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin = { Max: 1, Min: 0, Count: 3 }; hqChart.Frame.SubFrame[windowIndex].Frame.YSplitScale = [0.2,0.4]; var titleIndex = windowIndex + 1; hqChart.TitlePaint[titleIndex].Data[1] = new DynamicTitleData(paint[1].Data, this.Index[1].Name, this.Index[1].LineColor); hqChart.TitlePaint[titleIndex].Data[1].DataType = "MultiReport"; hqChart.TitlePaint[titleIndex].Title = this.FormatIndexTitle(); return true; } } //是否是指数代码 function IsIndexSymbol(symbol) { var upperSymbol = symbol.toUpperCase(); if (upperSymbol.indexOf('.SH') > 0) { upperSymbol = upperSymbol.replace('.SH', ''); if (upperSymbol.charAt(0) == '0' && parseInt(upperSymbol) <= 3000) return true; } else if (upperSymbol.indexOf('.SZ') > 0) { upperSymbol = upperSymbol.replace('.SZ', ''); if (upperSymbol.charAt(0) == '3' && upperSymbol.charAt(1) == '9') return true; } else if (upperSymbol.indexOf('.CI') > 0) //自定义指数 { return true; } return false; } //导出统一使用JSCommon命名空间名 module.exports = { JSCommon: { JSCanvasElement: JSCanvasElement, JSChart: JSChart, Guid: Guid, IFrameSplitOperator: IFrameSplitOperator, ChartData: ChartData, DataPlus: DataPlus, KLineTooltipPaint: KLineTooltipPaint, MARKET_SUFFIX_NAME: MARKET_SUFFIX_NAME, JSCommonCoordinateData:JSCommonCoordinateData, FrameSplitKLineX:FrameSplitKLineX, FrameSplitKLinePriceY:FrameSplitKLinePriceY, JSCHART_EVENT_ID:JSCHART_EVENT_ID }, };