/* Copyright (c) 2018 jones http://www.apache.org/licenses/LICENSE-2.0 开源项目 https://github.com/jones2000/HQChart jones_2000@163.com 封装行情类图形控件 (H5版本) */ function JSChart(divElement) { this.DivElement=divElement; this.DivToolElement=null; //工具条 this.JSChartContainer; //画图控件 //h5 canvas this.CanvasElement=document.createElement("canvas"); this.CanvasElement.className='jschart-drawing'; this.CanvasElement.id=Guid(); this.CanvasElement.setAttribute("tabindex",0); if (this.CanvasElement.style) this.CanvasElement.style.outline='none'; if(!divElement.hasChildNodes("canvas")){ divElement.appendChild(this.CanvasElement); } //改参数div this.ModifyIndexDialog=new ModifyIndexDialog(divElement); this.ChangeIndexDialog=new ChangeIndexDialog(divElement); this.MinuteDialog=new MinuteDialog(divElement); this.OnSize=function() { //画布大小通过div获取 var height=parseInt(this.DivElement.style.height.replace("px","")); if (this.ToolElement) { //TODO调整工具条大小 height-=this.ToolElement.style.height.replace("px",""); //减去工具条的高度 } this.CanvasElement.height=height; this.CanvasElement.width=parseInt(this.DivElement.style.width.replace("px","")); this.CanvasElement.style.width=this.CanvasElement.width+'px'; this.CanvasElement.style.height=this.CanvasElement.height+'px'; var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 this.CanvasElement.height*=pixelTatio; this.CanvasElement.width*=pixelTatio; console.log(`[JSChart::OnSize] devicePixelRatio=${window.devicePixelRatio}, height=${this.CanvasElement.height}, width=${this.CanvasElement.width}`); if (this.JSChartContainer && this.JSChartContainer.Frame) this.JSChartContainer.Frame.SetSizeChage(true); if (this.JSChartContainer) this.JSChartContainer.Draw(); } //手机屏需要调整 间距 this.AdjustChartBorder=function(chart) { var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 chart.Frame.ChartBorder.Left*=pixelTatio; chart.Frame.ChartBorder.Right*=pixelTatio; chart.Frame.ChartBorder.Top*=pixelTatio; chart.Frame.ChartBorder.Bottom*=pixelTatio; } this.AdjustTitleHeight=function(chart) { var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 for(let i in chart.Frame.SubFrame) { chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight*=pixelTatio; } chart.ChartCorssCursor.TextHeight*=pixelTatio; //十字光标文本信息高度 } //历史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; //创建改参数div chart.ModifyIndexDialog=this.ModifyIndexDialog; chart.ChangeIndexDialog=this.ChangeIndexDialog; chart.MinuteDialog=this.MinuteDialog; //右键菜单 if (option.IsShowRightMenu==true) chart.RightMenu=new KLineRightMenu(this.DivElement); if (option.ScriptError) chart.ScriptErrorCallback=option.ScriptError; chart.SelectRectRightMenu=new KLineSelectRightMenu(this.DivElement); if (option.EnableScrollUpDown==true) chart.EnableScrollUpDown=option.EnableScrollUpDown; if (option.DisableMouse==true) chart.DisableMouse=option.DisableMouse; 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.IndexTreeApiUrl) chart.ChangeIndexDialog.IndexTreeApiUrl=option.KLine.IndexTreeApiUrl; if (option.KLine.KLineDoubleClick==false) chart.MinuteDialog=this.MinuteDialog=null; if (option.KLine.IndexTreeApiUrl!=null) chart.ChangeIndexDialog.IndexTreeApiUrl=option.KLine.IndexTreeApiUrl; 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.KLine.FirstShowDate>20000101) chart.CustomShow={ Date:option.KLine.FirstShowDate }; } if (option.Page) { if (option.Page.Day && option.Page.Day.Enable==true) chart.Page.Day.Enable=true; if (option.Page.Minute && option.Page.Minute.Enable==true) chart.Page.Minute.Enable=true; } 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.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.DrawPicture) //画图工具 { if (option.DrawPicture.StorageKey && chart.ChartDrawStorage) chart.ChartDrawStorage.Load(option.DrawPicture.StorageKey); } if (option.StepPixel>0) chart.StepPixel=option.StepPixel; if (option.ZoomStepPixel>0) chart.ZoomStepPixel=option.ZoomStepPixel; if (option.IsApiPeriod==true) chart.IsApiPeriod=option.IsApiPeriod; 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; } this.AdjustChartBorder(chart); if (option.KLine) { if (option.KLine.PageSize > 0) //一屏显示的数据个数 { let pageSize = chart.GetMaxMinPageSize(); if (pageSize.Max>10 && pageSize.Max < option.KLine.PageSize) chart.PageSize = pageSize.Max; else if (pageSize.Min>10 && pageSize.Min> option.KLine.PageSize) chart.PageSize=pageSize.Min; else chart.PageSize = option.KLine.PageSize; } } //取消显示十字光标刻度信息 if (option.IsCorssOnlyDrawKLine===true) chart.ChartCorssCursor.IsOnlyDrawKLine=option.IsCorssOnlyDrawKLine; if (option.CorssCursorTouchEnd===true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd; if (option.IsClickShowCorssCursor==true) chart.IsClickShowCorssCursor=option.IsClickShowCorssCursor; 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.PressTime) chart.PressTime=option.CorssCursorInfo.PressTime; //长按显示十字光标的时间 } if (option.SplashTitle) chart.ChartSplashPaint.SplashTitle=option.SplashTitle; 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 (IFrameSplitOperator.IsNumber(item.FloatPrecision)) chart.Frame.SubFrame[i].Frame.YSplitOperator.FloatPrecision=item.FloatPrecision; if (item.Custom) chart.Frame.SubFrame[i].Frame.YSplitOperator.Custom=item.Custom; if (!isNaN(item.Height)) chart.Frame.SubFrame[i].Height = item.Height; if (item.IsShowLeftText===false || item.IsShowLeftText===true) { chart.Frame.SubFrame[i].Frame.IsShowYText[0]=item.IsShowLeftText; chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText; //显示左边刻度 } if (item.IsShowRightText===false || item.IsShowRightText===true) { chart.Frame.SubFrame[i].Frame.IsShowYText[1]=item.IsShowRightText; chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowRightText=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 (option.KLine) { if (option.KLine.ShowKLine == false) chart.ChartPaint[0].IsShow = false; if (option.KLine.InfoPosition>0) chart.ChartPaint[0].InfoPosition=option.KLine.InfoPosition; } 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.Overlay) { for(var i in option.Overlay) { var item=option.Overlay[i]; chart.OverlaySymbol(item.Symbol,item); } } if (option.ExtendChart) { for(var i in option.ExtendChart) { var item=option.ExtendChart[i]; chart.CreateExtendChart(item.Name, item); } } //创建子窗口的指标 let scriptData = new JSIndexScript(); if (option.ColorIndex) //五彩K线 { var item=option.ColorIndex; let indexInfo=scriptData.Get(item.Index); if (indexInfo) { indexInfo.ID=item.Index; 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) { indexInfo.ID=item.Index; 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.JsonData) { chart.WindowIndex[i]=new JsonDataIndex(item.Name,item.Script,item.Args,item); //脚本执行 } else if (item.Local && item.Local.Data) { chart.WindowIndex[i]=new LocalJsonDataIndex(item.Local.Name,item.Local.Args,{JsonData:item.Local.Data}); } 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 { 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; 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.Close!=null) chart.Frame.SubFrame[i].Frame.CloseIndex=item.Close; if (item.Overlay!=null) chart.Frame.SubFrame[i].Frame.OverlayIndex=item.Overlay; if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight; } //叠加指标宽度 if (option.OverlayIndexFrameWidth>40) chart.OverlayIndexFrameWidth=option.OverlayIndexFrameWidth; //叠加指标 for (var i in option.OverlayIndex) { var item=option.OverlayIndex[i]; if (item.Windows>=chart.Frame.SubFrame.length) continue; chart.CreateOverlayWindowsIndex( { WindowIndex:item.Windows,IndexName: item.Index, ShowRightText:item.ShowRightText } ); } this.AdjustTitleHeight(chart); return chart; } //自定义指数历史K线图 this.CreateCustomKLineChartContainer=function(option) { var chart=new CustomKLineChartContainer(this.CanvasElement); //创建改参数div chart.ModifyIndexDialog=this.ModifyIndexDialog; chart.ChangeIndexDialog=this.ChangeIndexDialog; chart.MinuteDialog=this.MinuteDialog; //右键菜单 if (option.IsShowRightMenu==true) chart.RightMenu=new KLineRightMenu(this.DivElement); 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.IndexTreeApiUrl) chart.ChangeIndexDialog.IndexTreeApiUrl=option.KLine.IndexTreeApiUrl; if (option.KLine.KLineDoubleClick==false) chart.MinuteDialog=this.MinuteDialog=null; if (option.KLine.IndexTreeApiUrl!=null) chart.ChangeIndexDialog.IndexTreeApiUrl=option.KLine.IndexTreeApiUrl; 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 (!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 (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(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 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.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.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.Info && option.Info.length>0) chart.SetMinuteInfo(option.Info,false); chart.Create(windowsCount); //创建子窗口 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.MinuteInfo) chart.CreateMinuteInfo(option.MinuteInfo); if (option.IsShowRightMenu==true) chart.RightMenu=new MinuteRightMenu(this.DivElement); if (option.DayCount>1) chart.DayCount=option.DayCount; 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.SplashTitle) chart.ChartSplashPaint.SplashTitle=option.SplashTitle; this.AdjustChartBorder(chart); 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.IsShowLeftText==false) chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText; //显示左边刻度 if (item.IsShowRightText==false) chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowRightText=item.IsShowRightText; //显示右边刻度 if (item.Height>0) chart.Frame.SubFrame[i].Height = item.Height; } } if (option.ExtendChart) { for(var i in option.ExtendChart) { var item=option.ExtendChart[i]; chart.CreateExtendChart(item.Name, item); } } //叠加股票 if (option.Overlay) { for(var i in option.Overlay) { var item=option.Overlay[i]; chart.OverlaySymbol(item.Symbol); } } if (option.MinuteLine) { if (option.MinuteLine.IsDrawAreaPrice==false) chart.ChartPaint[0].IsDrawArea=false; if (option.MinuteLine.IsShowLead==false) chart.IsShowLead=false; if (option.MinuteLine.IsShowAveragePrice==false) chart.ChartPaint[1].IsShow=false; if (option.MinuteLine.SplitType===1) chart.Frame.SubFrame[0].Frame.YSplitOperator.SplitType=option.MinuteLine.SplitType; } if(option.MinuteTitle) { if(option.MinuteTitle.IsShowName==false) chart.TitlePaint[0].IsShowName=false; if(option.MinuteTitle.IsShowDate===false || option.MinuteTitle.IsShowDate===true) chart.TitlePaint[0].IsShowDate=option.MinuteTitle.IsShowDate; //if(option.KLineTitle.IsShow == false) chart.TitlePaint[0].IsShow = false; } if (option.CorssCursorTouchEnd===true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd; if (option.IsShowBeforeData===true) chart.IsShowBeforeData=option.IsShowBeforeData; //分钟数据指标从第3个指标窗口设置 let scriptData = new JSIndexScript(); for(var i in option.Windows) { var item=option.Windows[i]; if (item.Script) { chart.WindowIndex[2+parseInt(i)]=new ScriptIndex(item.Name,item.Script,item.Args); //脚本执行 } else if (item.API) //使用API挂接指标数据 API:{ Name:指标名字, Script:指标脚本可以为空, Args:参数可以为空, Url:指标执行地址 } { var apiItem=item.API; chart.WindowIndex[2+parseInt(i)]=new APIScriptIndex(apiItem.Name,apiItem.Script,apiItem.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; indexInfo.ID=item.Index; var args=indexInfo.Args; if (item.Args) args=item.Args; 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; } this.AdjustTitleHeight(chart); if (option.Function) { var func=option.Function; if (func.RequestMinuteData) chart.RequestMinuteData=func.RequestMinuteData; if (func.RecvMinuteData) chart.RecvMinuteData=func.RecvMinuteData; } 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; } let scriptData = new JSIndexScript(); for(var i in option.Windows) { var item=option.Windows[i]; if (item.Script) { chart.WindowIndex[2+parseInt(i)]=new ScriptIndex(item.Name,item.Script,item.Args); //脚本执行 } 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; chart.WindowIndex[2+parseInt(i)] = new ScriptIndex(indexInfo.Name, indexInfo.Script, indexInfo.Args); //脚本执行 } } if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[2+parseInt(i)].Frame.ChartBorder.TitleHeight=item.TitleHeight; } chart.TradeDate=20181009; 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; //创建改参数div chart.ModifyIndexDialog=this.ModifyIndexDialog; chart.ChangeIndexDialog=this.ChangeIndexDialog; if (option.ScriptError) chart.ScriptErrorCallback=option.ScriptError; 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.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; } this.AdjustChartBorder(chart); if (option.IsShowCorssCursorInfo==false) chart.ChartCorssCursor.IsShowText=option.IsShowCorssCursorInfo; //取消显示十字光标刻度信息 if (option.IsCorssOnlyDrawKLine===true) chart.ChartCorssCursor.IsOnlyDrawKLine=option.IsCorssOnlyDrawKLine; if (option.CorssCursorTouchEnd===true) chart.CorssCursorTouchEnd = option.CorssCursorTouchEnd; if (option.IsClickShowCorssCursor==true) chart.IsClickShowCorssCursor=option.IsClickShowCorssCursor; 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.IsShowLeftText==false) chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowLeftText=item.IsShowLeftText; //显示左边刻度 if (item.IsShowRightText==false) chart.Frame.SubFrame[i].Frame.YSplitOperator.IsShowRightText=item.IsShowRightText; //显示右边刻度 } } if (option.ExtendChart) { for(var i in option.ExtendChart) { var item=option.ExtendChart[i]; chart.CreateExtendChart(item.Name, item); } } //股票名称 日期 周期都不显示 chart.TitlePaint[0].IsShowName=false; chart.TitlePaint[0].IsShowSettingInfo=false; chart.TitlePaint[0].IsShowDateTime=false; //创建子窗口的指标 let scriptData = new 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 (item.Close!=null) chart.Frame.SubFrame[i].Frame.CloseIndex=item.Close; if (!isNaN(item.TitleHeight)) chart.Frame.SubFrame[i].Frame.ChartBorder.TitleHeight=item.TitleHeight; } this.AdjustTitleHeight(chart); return chart; } //根据option内容绘制图形 this.SetOption=function(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 "简单图形": return this.CreateSimpleChart(option); case "饼图": case '雷达图': return this.CreatePieChart(option); case '地图': return this.CreateMapChart(option); default: return false; } if (!chart) return false; //是否自动更新 if (option.IsAutoUpdate!=null) chart.IsAutoUpdate=option.IsAutoUpdate; if (option.AutoUpdateFrequency>0) chart.AutoUpdateFrequency=option.AutoUpdateFrequency; //设置股票代码 if (!option.Symbol) return false; chart.Draw(); chart.ChangeSymbol(option.Symbol); this.JSChartContainer=chart; this.DivElement.JSChart=this; //div中保存一份 this.JSChartContainer.Draw(); } this.CreateSimpleChart=function(option) { var chart=new SimlpleChartContainer(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; } chart.Draw(); chart.RequestData(); this.JSChartContainer=chart; this.DivElement.JSChart=this; //div中保存一份 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; } this.AdjustChartBorder(chart); if (option.Frame) { if (option.Frame[0].IsShowBorder == false) chart.Frame.IsShowBorder = option.Frame[0].IsShowBorder; } chart.Draw(); chart.RequestData(); this.JSChartContainer=chart; this.DivElement.JSChart=this; //div中保存一份 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; } chart.Draw(); chart.RequestData(); this.JSChartContainer=chart; this.DivElement.JSChart=this; //div中保存一份 this.JSChartContainer.Draw(); } //创建工具条 this.CreateToolbar=function(option) { } //创建设置div窗口 this.CreateSettingDiv=function(option) { } this.Focus=function() { if (this.CanvasElement) this.CanvasElement.focus(); } //切换股票代码接口 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); } this.ChangeScriptIndex=function(windowIndex,indexData) { if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeScriptIndex)=='function') this.JSChartContainer.ChangeScriptIndex(windowIndex,indexData); } this.ChangePyScriptIndex=function(windowIndex, indexData) //切换py指标 { if (this.JSChartContainer && typeof(this.JSChartContainer.ChangePyScriptIndex)=='function') this.JSChartContainer.ChangePyScriptIndex(windowIndex,indexData); } this.GetIndexInfo=function() { if (this.JSChartContainer && typeof(this.JSChartContainer.GetIndexInfo)=='function') return this.JSChartContainer.GetIndexInfo(); else return []; } 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.CancelInstructionIndex=function() { if (this.JSChartContainer && typeof(this.JSChartContainer.CancelInstructionIndex)=='function') this.JSChartContainer.CancelInstructionIndex(); } //K线周期切换 this.ChangePeriod=function(period) { if (this.JSChartContainer && typeof(this.JSChartContainer.ChangePeriod)=='function') this.JSChartContainer.ChangePeriod(period); } //K线复权切换 this.ChangeRight=function(right) { if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeRight)=='function') this.JSChartContainer.ChangeRight(right); } //叠加股票 this.OverlaySymbol=function(symbol,option) { if (this.JSChartContainer && typeof(this.JSChartContainer.OverlaySymbol)=='function') this.JSChartContainer.OverlaySymbol(symbol,option); } //删除一个叠加股票 this.DeleteOverlaySymbol=function(symbol) { if (this.JSChartContainer && typeof(this.JSChartContainer.DeleteOverlaySymbol)=='function') this.JSChartContainer.DeleteOverlaySymbol(symbol); } //设置当前屏的起始日期 { Date:起始日期(必填), PageSize:一屏显示的数据个数(可选)} this.SetFirstShowDate=function(obj) { if (this.JSChartContainer && typeof(this.JSChartContainer.SetFirstShowDate)=='function') this.JSChartContainer.SetFirstShowDate(obj); } //K线切换类型 0=实心K线 1=收盘价线 2=美国线 3=空心K线 this.ChangeKLineDrawType=function(drawType) { if (this.JSChartContainer && typeof(this.JSChartContainer.ChangeKLineDrawType)=='function') this.JSChartContainer.ChangeKLineDrawType(drawType); } //指标窗口个数 this.ChangeIndexWindowCount = function(count){ if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeIndexWindowCount) == 'function'){ this.JSChartContainer.ChangeIndexWindowCount(count); } } //取消叠加 this.ClearOverlaySymbol = function(){ if(this.JSChartContainer && typeof(this.JSChartContainer.ClearOverlaySymbol) == 'function'){ this.JSChartContainer.ClearOverlaySymbol(); } } this.DeleteKLineInfo=function(infoName) { if(this.JSChartContainer && typeof(this.JSChartContainer.DeleteKLineInfo) == 'function') { this.JSChartContainer.DeleteKLineInfo(infoName); } } this.ClearKLineInfo=function() { if(this.JSChartContainer && typeof(this.JSChartContainer.ClearKLineInfo) == 'function') { this.JSChartContainer.ClearKLineInfo(); } } this.AddKLineInfo=function(infoName, bUpdate) { if(this.JSChartContainer && typeof(this.JSChartContainer.AddKLineInfo) == 'function') { this.JSChartContainer.AddKLineInfo(infoName,bUpdate); } } this.ChangMainDataControl=function(dataControl) { if (this.JSChartContainer && typeof(this.JSChartContainer.SetMainDataConotrl)=='function') this.JSChartContainer.SetMainDataConotrl(dataControl); } this.AddOverlayIndex=function(obj) //{WindowIndex:窗口ID, IndexName:指标ID, Identify:叠加指标ID(可选)} { if (this.JSChartContainer && typeof(this.JSChartContainer.AddOverlayIndex)=='function') this.JSChartContainer.AddOverlayIndex(obj); } this.DeleteOverlayWindowsIndex=function(identify) { if (this.JSChartContainer && typeof(this.JSChartContainer.DeleteOverlayWindowsIndex)=='function') this.JSChartContainer.DeleteOverlayWindowsIndex(identify); } this.StopAutoUpdate=function() { if (this.JSChartContainer && typeof(this.JSChartContainer.StopAutoUpdate)=='function') this.JSChartContainer.StopAutoUpdate(); } //设置强制横屏 this.ForceLandscape=function(bForceLandscape) { if (this.JSChartContainer) { console.log("[JSChart::ForceLandscape] bForceLandscape="+bForceLandscape); this.JSChartContainer.IsForceLandscape=bForceLandscape; } } //锁指标 this.LockIndex=function(lockData) { if(this.JSChartContainer && typeof(this.JSChartContainer.LockIndex)=='function') { console.log('[JSChart:LockIndex] lockData', lockData); this.JSChartContainer.LockIndex(lockData); } } //历史分钟数据 更改日期 this.ChangeTradeDate=function(tradeDate) { if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeTradeDate)=='function') { console.log('[JSChart:ChangeTradeDate] date', tradeDate); this.JSChartContainer.ChangeTradeDate(tradeDate); } } //多日走势图 this.ChangeDayCount=function(count) { if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeDayCount)=='function') { console.log('[JSChart:ChangeDayCount] count', count); this.JSChartContainer.ChangeDayCount(count); } } //返回弹幕数据类 this.StartAnimation=function(option) { if(this.JSChartContainer && typeof(this.JSChartContainer.StartAnimation)=='function') { console.log('[JSChart:StartAnimation] start.'); return this.JSChartContainer.StartAnimation(option); } } this.StopAnimation=function() { if(this.JSChartContainer && typeof(this.JSChartContainer.StopAnimation)=='function') { console.log('[JSChart:StopAnimation] start.'); return this.JSChartContainer.StopAnimation(); } } this.SaveToImage = function (format,colorGB) //format=保存的文件格式, colorGB=背景色 { if (this.JSChartContainer && typeof (this.JSChartContainer.SaveToImage) == 'function') return this.JSChartContainer.SaveToImage(format,colorGB); } this.SaveToImageUrl=function(obj, callback) { if (this.JSChartContainer && typeof (this.JSChartContainer.SaveToImageUrl) == 'function') return this.JSChartContainer.SaveToImageUrl(obj, callback); } //事件回调 this.AddEventCallback=function(obj) { if(this.JSChartContainer && typeof(this.JSChartContainer.AddEventCallback)=='function') { console.log('[JSChart:AddEventCallback] ', obj); this.JSChartContainer.AddEventCallback(obj); } } //设置语言 'EN', 'CN' this.SetLanguage=function(language) { if(this.JSChartContainer && typeof(this.JSChartContainer.SetLanguage)=='function') { console.log('[JSChart:SetLanguage] ', language); this.JSChartContainer.SetLanguage(language); } } //切换指标模板 this.ChangeIndexTemplate=function(option) { if(this.JSChartContainer && typeof(this.JSChartContainer.ChangeIndexTemplate)=='function') { console.log('[JSChart:ChangeIndexTemplate] ', option); this.JSChartContainer.ChangeIndexTemplate(option); } } } //初始化 JSChart.Init=function(divElement) { var jsChartControl=new JSChart(divElement); jsChartControl.OnSize(); return jsChartControl; } JSChart.SetDomain=function(domain,cacheDomain) { if (domain) g_JSChartResource.Domain=domain; if (cacheDomain) g_JSChartResource.CacheDomain=cacheDomain; } JSChart.SetPyIndexDomain=function(domain) //设置py指标计算api域名 { if (domain) g_JSChartResource.PyIndexDomain=domain; } //自定义风格 JSChart.SetStyle=function(option) { if (option) g_JSChartResource.SetStyle(option); } //value { EN:'', CH:'' } JSChart.SetTextResource=function(key,value) { g_JSChartLocalization.SetTextResource(key,value); } //获取本地化资源 JSChart.GetLocalization=function() { return g_JSChartLocalization; } //获取设备分辨率比 JSChart.GetDevicePixelRatio=function() { return GetDevicePixelRatio(); } JSChart.CreateGuid=function() { return Guid(); } JSChart.GetResource=function() //获取颜色配置 (设置配必须啊在JSChart.Init()之前) { return g_JSChartResource; } JSChart.GetMinuteTimeStringData=function() { return g_MinuteTimeStringData; } JSChart.GetMinuteCoordinateData=function() { return g_MinuteCoordinateData; } var JSCHART_EVENT_ID= { RECV_KLINE_MATCH:1, //接收到形态匹配 RECV_INDEX_DATA:2, //接收指标数据 RECV_HISTROY_DATA:3,//接收到历史数据 RECV_TRAIN_MOVE_STEP:4, //接收K线训练,移动一次K线 CHART_STATUS:5, //每次Draw() 以后会调用 BARRAGE_PLAY_END:6, //单个弹幕播放完成 RECV_OVERLAY_INDEX_DATA:7,//接收叠加指标数据 DBCLICK_KLINE:8, //双击K线图 RECV_START_AUTOUPDATE:9, //开始自动更新 RECV_STOP_AUTOUPDATE:10, //停止自动更新 ON_CONTEXT_MENU:11, //右键菜单事件 ON_TITLE_DRAW:12, //标题信息绘制事件 } 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.ChartDrawStorage; //画图工具保存 this.CurrentChartDrawPicture=null; //当前的画图工具 this.SelectChartDrawPicture=null; //当前选中的画图 this.ChartCorssCursor; //十字光标 this.IsClickShowCorssCursor=false; //手势点击显示十字光标 this.ChartSplashPaint=null; //等待提示 this.Canvas=uielement.getContext("2d"); //画布 this.UIElement=uielement; this.MouseDrag; this.DragMode=1; //拖拽模式 0 禁止拖拽 1 数据拖拽 2 区间选择 this.DragTimer; this.EnableScrollUpDown=false; //是否可以上下滚动图形((手机端才有)) this.CursorIndex=0; //十字光标X轴索引 this.LastPoint=new Point(); //鼠标位置 this.IsForceLandscape=false; //是否强制横屏 this.CorssCursorTouchEnd = false; //手离开屏幕自动隐藏十字光标 this.StepPixel=4; //移动一个数据需要的像素 this.ZoomStepPixel=5; //放大缩小手势需要的最小像素 this.EnableAnimation=false; //是否开启动画 //tooltip提示信息 this.Tooltip=document.createElement("div"); this.Tooltip.className='jschart-tooltip'; this.Tooltip.style.background=g_JSChartResource.TooltipBGColor; this.Tooltip.style.opacity=g_JSChartResource.TooltipAlpha; this.Tooltip.id=Guid(); uielement.parentNode.appendChild(this.Tooltip); this.IsShowTooltip=true; //是否显示K线tooltip //区间选择 this.SelectRect=document.createElement("div"); this.SelectRect.className="jschart-selectrect"; this.SelectRect.style.background=g_JSChartResource.SelectRectBGColor; //this.SelectRect.style.opacity=g_JSChartResource.SelectRectAlpha; this.SelectRect.id=Guid(); uielement.parentNode.appendChild(this.SelectRect); //区间选择右键菜单 this.SelectRectRightMenu; //坐标轴风格方法 double-更加数值型分割 price-更加股票价格分割 this.FrameSplitData=new Map(); this.FrameSplitData.set("double",new SplitData()); this.FrameSplitData.set("price",new PriceSplitData()); //事件回调 this.mapEvent=new Map(); //通知外部调用 key:JSCHART_EVENT_ID value:{Callback:回调,} this.IsOnTouch = false; //是否再操作数据 this.TouchDrawCount = 0; //手势绘制次数 this.DisableMouse=false; //禁止鼠标事件 this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; this.PressTime=500; this.NetworkFilter; //网络请求回调 function(data, callback); //设置事件回调 //{event:事件id, callback:回调函数} this.AddEventCallback=function(object) { 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.GetEventCallback=function(id) //获取事件回调 { if (!this.mapEvent.has(id)) return null; var item=this.mapEvent.get(id); return item; } //接收指标数据 this.GetIndexEvent=function() { return this.GetEventCallback(JSCHART_EVENT_ID.RECV_INDEX_DATA); } this.GetOverlayIndexEvent=function() { return this.GetEventCallback(JSCHART_EVENT_ID.RECV_OVERLAY_INDEX_DATA); } uielement.onmousemove=function(e) { //console.log('[uielement.onmousemove] e.clientX, e.clientY, left, top ',e.clientX, e.clientY, this.getBoundingClientRect().left,this.getBoundingClientRect().top); var pixelTatio = GetDevicePixelRatio(); //鼠标移动坐标是原始坐标 需要乘以放大倍速 var x = (e.clientX-this.getBoundingClientRect().left)*pixelTatio; var y = (e.clientY-this.getBoundingClientRect().top)*pixelTatio; //加载数据中,禁用鼠标事件 if (this.JSChartContainer.ChartSplashPaint && this.JSChartContainer.ChartSplashPaint.IsEnableSplash == true) return; if (this.JSChartContainer.DisableMouse==true) return; if(this.JSChartContainer) this.JSChartContainer.OnMouseMove(x,y,e); } uielement.oncontextmenu=function(e) { var x = e.clientX-this.getBoundingClientRect().left; var y = e.clientY-this.getBoundingClientRect().top; if(this.JSChartContainer && typeof(this.JSChartContainer.OnRightMenu)=='function') this.JSChartContainer.OnRightMenu(x,y,e); //右键菜单事件 return false; } uielement.onmousedown=function(e) { if(!this.JSChartContainer) return; if(this.JSChartContainer.DragMode==0) return; var pixelTatio = GetDevicePixelRatio(); this.JSChartContainer.IsOnTouch=true; if (this.JSChartContainer.TryClickLock) { //console.log('[uielement.onmousedown] left, top ',e.clientX, e.clientY, this.getBoundingClientRect().left,this.getBoundingClientRect().top); var x = (e.clientX-this.getBoundingClientRect().left)*pixelTatio; var y = (e.clientY-this.getBoundingClientRect().top)*pixelTatio; if (this.JSChartContainer.TryClickLock(x,y)) return; } this.JSChartContainer.HideSelectRect(); if (this.JSChartContainer.SelectRectRightMenu) this.JSChartContainer.SelectRectRightMenu.Hide(); if (this.JSChartContainer.ChartPictureMenu) this.JSChartContainer.ChartPictureMenu.Hide(); 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; if (this.JSChartContainer.CurrentChartDrawPicture) //画图工具模式 { var drawPicture=this.JSChartContainer.CurrentChartDrawPicture; if (drawPicture.Status==2) this.JSChartContainer.SetChartDrawPictureThirdPoint(drag.Click.X,drag.Click.Y); else { this.JSChartContainer.SetChartDrawPictureFirstPoint(drag.Click.X,drag.Click.Y); //只有1个点 直接完成 if (this.JSChartContainer.FinishChartDrawPicturePoint()) this.JSChartContainer.DrawDynamicInfo(); } } else //是否在画图工具上 { var drawPictrueData={}; var pixelTatio = GetDevicePixelRatio(); //鼠标移动坐标是原始坐标 需要乘以放大倍速 drawPictrueData.X=(e.clientX-this.getBoundingClientRect().left)*pixelTatio; drawPictrueData.Y=(e.clientY-this.getBoundingClientRect().top)*pixelTatio; if (this.JSChartContainer.GetChartDrawPictureByPoint(drawPictrueData)) { drawPictrueData.ChartDrawPicture.Status=20; drawPictrueData.ChartDrawPicture.ValueToPoint(); drawPictrueData.ChartDrawPicture.MovePointIndex=drawPictrueData.PointIndex; this.JSChartContainer.CurrentChartDrawPicture=drawPictrueData.ChartDrawPicture; this.JSChartContainer.SelectChartDrawPicture=drawPictrueData.ChartDrawPicture; this.JSChartContainer.OnSelectChartPicture(drawPictrueData.ChartDrawPicture); //选中画图工具事件 } } 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.X-e.clientX); if (this.JSChartContainer.CurrentChartDrawPicture) { var drawPicture=this.JSChartContainer.CurrentChartDrawPicture; if (drawPicture.Status==1 || drawPicture.Status==2) { if(Math.abs(drag.LastMove.X-e.clientX)<5 && Math.abs(drag.LastMove.Y-e.clientY)<5) return; if(this.JSChartContainer.SetChartDrawPictureSecondPoint(e.clientX,e.clientY)) { this.JSChartContainer.DrawDynamicInfo(); } } else if (drawPicture.Status==3) { if(this.JSChartContainer.SetChartDrawPictureThirdPoint(e.clientX,e.clientY)) { this.JSChartContainer.DrawDynamicInfo(); } } else if (drawPicture.Status==20) //画图工具移动 { if(Math.abs(drag.LastMove.X-e.clientX)<5 && Math.abs(drag.LastMove.Y-e.clientY)<5) return; if(this.JSChartContainer.MoveChartDrawPicture(e.clientX-drag.LastMove.X,e.clientY-drag.LastMove.Y)) { this.JSChartContainer.DrawDynamicInfo(); } } drag.LastMove.X=e.clientX; drag.LastMove.Y=e.clientY; } else if (this.JSChartContainer.DragMode==1) //数据左右拖拽 { if (moveSetp<5) return; var isLeft=true; if (drag.LastMove.X0 && moveSetp<=3 && this.JSChartContainer.EnableScrollUpDown==true) { clearTimeout(this.DragTimer); this.DragTimer=null; return; } if (moveSetp<5) { jsChart.PreventTouchEvent(e); return; } var isLeft=true; if (drag.LastMove.X0) //放大 { var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.JSChartContainer.CursorIndex-0.5).toFixed(0)); if (!this.JSChartContainer.Frame.ZoomUp(cursorIndex)) return; this.JSChartContainer.CursorIndex=cursorIndex.Index; this.JSChartContainer.UpdatePointByCursorIndex(); this.JSChartContainer.UpdataDataoffset(); this.JSChartContainer.UpdateFrameMaxMin(); this.JSChartContainer.Draw(); this.JSChartContainer.ShowTooltipByKeyDown(); } else //缩小 { var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.JSChartContainer.CursorIndex-0.5).toFixed(0)); if (!this.JSChartContainer.Frame.ZoomDown(cursorIndex)) return; this.JSChartContainer.CursorIndex=cursorIndex.Index; this.JSChartContainer.UpdataDataoffset(); this.JSChartContainer.UpdatePointByCursorIndex(); this.JSChartContainer.UpdateFrameMaxMin(); this.JSChartContainer.Draw(); this.JSChartContainer.ShowTooltipByKeyDown(); } phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY}; } jsChart.PreventTouchEvent(e); }; uielement.ontouchend=function(e) { console.log('[KLineChartContainer::uielement.ontouchend]',e); this.JSChartContainer.IsOnTouch = false; this.JSChartContainer.OnTouchFinished(); this.JSChartContainer.TouchDrawCount=0; clearTimeout(this.DragTimer); } } this.Draw=function() { if (this.UIElement.width<=0 || this.UIElement.height<=0) return; this.Canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height); var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 this.Canvas.lineWidth=pixelTatio; //手机端需要根据分辨率比调整线段宽度 if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash) { this.Frame.Draw(); this.ChartSplashPaint.Draw(); return; } //框架 this.Frame.Draw(); this.Frame.CalculateLock(); //框架内图形 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(); } if (this.Frame.DrawOveraly) this.Frame.DrawOveraly(); //画叠加指标 //固定扩展图形 for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (!item.IsDynamic && item.IsAnimation==false) 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(); this.Frame.Snapshot(); for(var i in this.ExtendChartPaint) //动态扩展图形 { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.DrawAfterTitle===false) item.Draw(); } if (this.LastPoint.X!=null || this.LastPoint.Y!=null) { if (this.ChartCorssCursor) { this.ChartCorssCursor.LastPoint=this.LastPoint; this.ChartCorssCursor.CursorIndex=this.CursorIndex; //移动端 拖拽数据的时候 不显示十字光标, 没有按屏的时候也不显示十字光标 if (!(this.CorssCursorTouchEnd===true && this.MouseDrag) && !(this.CorssCursorTouchEnd==true && this.IsOnTouch==false) ) this.ChartCorssCursor.Draw(); } } var eventTitleDraw=this.GetEventCallback(JSCHART_EVENT_ID.ON_TITLE_DRAW); for(var i in this.TitlePaint) { var item=this.TitlePaint[i]; if (!item.IsDynamic) continue; item.CursorIndex=this.CursorIndex; item.OnDrawEvent=eventTitleDraw; item.Draw(); } for(var i in this.ExtendChartPaint) //动态扩展图形 { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.DrawAfterTitle===true && item.IsAnimation==false) item.Draw(); } if (this.EnableAnimation) { for(var i in this.ExtendChartPaint) //动画 { var item=this.ExtendChartPaint[i]; if (item.IsAnimation===true) item.Draw(); } } for(var i in this.ChartDrawPicture) { var item=this.ChartDrawPicture[i]; item.Draw(); } if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.Status!=10) { this.CurrentChartDrawPicture.Draw(); } //发送图形状态给外部 if (this.mapEvent.has(JSCHART_EVENT_ID.CHART_STATUS)) { var event=this.mapEvent.get(JSCHART_EVENT_ID.CHART_STATUS); var data={ }; if (typeof(this.GetChartStatus)=='function') data=this.GetChartStatus(); event.Callback(event,data,this); } ++this.TouchDrawCount; } //画动态信息 this.DrawDynamicInfo=function() { if (this.Frame.ScreenImageData==null) return; var isErase=false; if (this.ChartCorssCursor) { if (this.ChartCorssCursor.PointX!=null || this.ChartCorssCursor.PointY!=null) isErase=true; } isErase=true; //每次都擦除背景 if (isErase==false) { for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.IsEraseBG) { isErase=true; break; } } } if (isErase) this.Canvas.putImageData(this.Frame.ScreenImageData,0,0); for(var i in this.ExtendChartPaint) //动态扩展图形 { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.DrawAfterTitle===false && item.IsAnimation==false) item.Draw(); } if (this.ChartCorssCursor) { this.ChartCorssCursor.LastPoint=this.LastPoint; this.ChartCorssCursor.CursorIndex=this.CursorIndex; if ( !(this.IsOnTouch===false && this.CorssCursorTouchEnd===true)) this.ChartCorssCursor.Draw(); } for(var i in this.TitlePaint) { var item=this.TitlePaint[i]; if (!item.IsDynamic) continue; item.CursorIndex=this.CursorIndex; item.Draw(); } for(var i in this.ExtendChartPaint) //动态扩展图形 在动态标题以后画 { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.DrawAfterTitle===true) item.Draw(); } if (this.EnableAnimation) { for(var i in this.ExtendChartPaint) //动画 { var item=this.ExtendChartPaint[i]; if (item.IsAnimation===true) item.Draw(); } } for(var i in this.ChartDrawPicture) { var item=this.ChartDrawPicture[i]; item.Draw(); } if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.Status!=10) { this.CurrentChartDrawPicture.Draw(); } ++this.TouchDrawCount; } this.DrawAnimation=function() //绘制动画 如弹幕 { if (!this.EnableAnimation) return; if (this.Frame.ScreenImageData && !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; window.requestAnimationFrame(function() { self.DrawAnimation(); }); } this.StartAnimation=function(option) { 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; window.requestAnimationFrame(function() { self.DrawAnimation(); }); return barrageData; } this.StopAnimation=function() { this.EnableAnimation=false; this.DrawDynamicInfo(); } this.OnMouseMove=function(x,y,e) { this.LastPoint.X=x; this.LastPoint.Y=y; this.CursorIndex=this.Frame.GetXData(x); var bDrawPicture=false; //是否正在画图 if (this.CurrentChartDrawPicture) { if (this.CurrentChartDrawPicture.SetLastPoint) this.CurrentChartDrawPicture.SetLastPoint({X:x,Y:y}); bDrawPicture=true; } else { var drawPictrueData={}; drawPictrueData.X=x; drawPictrueData.Y=y; if (this.GetChartDrawPictureByPoint(drawPictrueData)) { if (drawPictrueData.PointIndex===100) this.UIElement.style.cursor="move"; else this.UIElement.style.cursor="pointer"; bDrawPicture=true; } else { if (!this.MouseDrag) this.UIElement.style.cursor="default"; } } this.DrawDynamicInfo(); if (this.IsShowTooltip && bDrawPicture==false) { 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) { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (item.GetTooltipData(x,y,toolTip)) { break; } } } if (toolTip.Data) { var xTooltip = e.clientX-this.UIElement.getBoundingClientRect().left; var yTooltip = e.clientY-this.UIElement.getBoundingClientRect().top; this.ShowTooltip(xTooltip,yTooltip,toolTip); } else { this.HideTooltip(); } } } this.OnKeyDown=function(e) { var keyID = e.keyCode ? e.keyCode :e.which; switch(keyID) { case 37: //left if (this.CursorIndex<=0.99999) { if (!this.DataMoveLeft()) break; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); this.ShowTooltipByKeyDown(); } else { --this.CursorIndex; this.UpdatePointByCursorIndex(); this.DrawDynamicInfo(); this.ShowTooltipByKeyDown(); } break; case 39: //right var xPointcount=0; if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount; else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount; if (this.CursorIndex+1>=xPointcount) { if (!this.DataMoveRight()) break; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); this.ShowTooltipByKeyDown(); } else { //判断是否在最后一个数据上 var data=null; if (this.Frame.Data) data=this.Frame.Data; else data=this.Frame.SubFrame[0].Frame.Data; if (!data) break; if (this.CursorIndex+data.DataOffset+1>=data.Data.length) break; ++this.CursorIndex; this.UpdatePointByCursorIndex(); this.DrawDynamicInfo(); this.ShowTooltipByKeyDown(); } break; case 38: //up var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0)); if (!this.Frame.ZoomUp(cursorIndex)) break; this.CursorIndex=cursorIndex.Index; this.UpdatePointByCursorIndex(); this.UpdataDataoffset(); this.UpdateFrameMaxMin(); this.Draw(); this.ShowTooltipByKeyDown(); break; case 40: //down var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0)); if (!this.Frame.ZoomDown(cursorIndex)) break; this.CursorIndex=cursorIndex.Index; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); this.ShowTooltipByKeyDown(); break; case 46: //del if (!this.SelectChartDrawPicture) break; var drawPicture=this.SelectChartDrawPicture; console.log(drawPicture,"drawPicturedrawPicturedrawPicture") this.SelectChartDrawPicture=null; this.ClearChartDrawPicture(drawPicture); //删除选中的画图工具 break; default: return; } //不让滚动条滚动 if(e.preventDefault) e.preventDefault(); else e.returnValue = false; } this.OnDoubleClick=function(x,y,e) { //console.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.ShowTooltipByKeyDown=function() { 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; var toolTip=new TooltipData(); toolTip.Data=data.Data[data.DataOffset+index]; toolTip.ChartPaint=this.ChartPaint[0]; var pixelTatio = GetDevicePixelRatio(); if (pixelTatio===0) pixelTatio=1; //div 缩放还是使用原始坐标 this.ShowTooltip(this.LastPoint.X/pixelTatio,this.LastPoint.Y/pixelTatio,toolTip); } this.ShowTooltip=function(x,y,toolTip) { if (!this.IsShowTooltip) return; var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 var xMove=15/pixelTatio; //顶部坐标偏移位置 if (toolTip.Type===0) //K线信息 { var format=new HistoryDataStringFormat(); format.Value=toolTip; format.Symbol=this.Symbol; format.LanguageID=this.LanguageID; if (!format.Operator()) return; var textHeight=format.LineCount*25; //每行的行高25 var scrollPos=GetScrollPosition(); var left = x; var top = y; var width=157; if (this.LanguageID==JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID) width=180; this.Tooltip.style.width = width+"px"; this.Tooltip.style.height =textHeight+"px"; //console.log(`[JSChartContainer::ShowTooltip] left=${left} top=${top} xMove=${xMove}` ); //if (toolTip.ChartPaint.Name=="Overlay-KLine") this.Tooltip.style.height =220+"px"; this.Tooltip.style.position = "absolute"; //console.log('[JSChartContainer::ShowTooltip] getBoundingClientRect() ',this.UIElement.getBoundingClientRect()) if (left+width>this.UIElement.getBoundingClientRect().width) this.Tooltip.style.left = (left-width) + "px"; else this.Tooltip.style.left = left + "px"; this.Tooltip.style.top = (top + xMove)+ "px"; this.Tooltip.className='jschart-tooltip'; this.Tooltip.innerHTML=format.Text; this.Tooltip.style.display = "block"; } else if (toolTip.Type===1) //信息地雷提示信息 { var scrollPos=GetScrollPosition(); var left = x; var top = y; var width=500; var format=new KLineInfoDataStringFormat(); format.Value=toolTip; format.Symbol=this.Symbol; if (!format.Operator()) return; this.Tooltip.className='jchart-klineinfo-tooltip'; this.Tooltip.style.position = "absolute"; if(left+width>this.UIElement.getBoundingClientRect().width){ this.Tooltip.style.left = (left-width) + "px"; }else{ this.Tooltip.style.left = left + "px"; } this.Tooltip.style.top = (top +xMove)+ "px"; this.Tooltip.style.width = width+"px"; this.Tooltip.style.height =null; this.Tooltip.innerHTML=format.Text; this.Tooltip.style.display = "block"; } } this.HideTooltip=function() { this.Tooltip.style.display = "none"; } this.ShowSelectRect=function(x,y,x2,y2) { var left = x; var top = y; var borderRight=this.Frame.ChartBorder.GetRight(); var borderLeft=this.Frame.ChartBorder.GetLeft(); if (x>borderRight) x=borderRight; if (x2>borderRight) x2=borderRight; if (xx2) left=x2; if (y>y2) top=y2; var width=Math.abs(x-x2); var height=Math.abs(y-y2); this.SelectRect.style.width = width+"px"; this.SelectRect.style.height =height+"px"; this.SelectRect.style.position = "absolute"; this.SelectRect.style.left = left +"px"; this.SelectRect.style.top = top +"px"; this.SelectRect.style.display = "block"; } this.UpdateSelectRect=function(start,end) { if (!this.ChartPaint[0].Data) return; var data=this.ChartPaint[0].Data; var offset=data.DataOffset; var fixedStart=start-offset; var fixedEnd=end-offset; var x=this.Frame.GetXFromIndex(fixedStart); var x2=this.Frame.GetXFromIndex(fixedEnd); console.log('[JSChartContainer::UpdateSelectRect]',start,end,x,x2); var scrollPos=GetScrollPosition(); this.SelectRect.style.left = x + scrollPos.Left+"px"; this.SelectRect.style.width = (x2-x)+"px"; } this.HideSelectRect=function() { this.SelectRect.style.display = "none"; } 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(this.ChartPaint[i]); } 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.Maxrange.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; } //更新子坐标 for(var i in this.Frame.SubFrame) { var subFrame=this.Frame.SubFrame[i]; for(var j in subFrame.OverlayIndex) { var overlayItem=subFrame.OverlayIndex[j]; overlayItem.UpdateFrameMaxMin(); } } } 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; } //叠加指标当前显示的数据偏移 for (var i in this.Frame.SubFrame) { var subFrame=this.Frame.SubFrame[i]; for(var j in subFrame.OverlayIndex) { var overlayItem=subFrame.OverlayIndex[j]; for(var k in overlayItem.ChartPaint) { var item=overlayItem.ChartPaint[k]; if (!item.Data) continue; item.Data.DataOffset=data.DataOffset; } } } } this.DataMove=function(step,isLeft) { step=parseInt(step/this.StepPixel); //除以4个像素 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 (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.beginPath(); 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)); //console.log('x='+ x +' date='+data.Data[data.DataOffset+index].Date); return data.DataOffset+index; } //获取主数据 this.GetSelectRectData=function(selectData) { if (Math.abs(selectData.XStart-selectData.XEnd)<5) 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 start=this.GetDataIndexByPoint(selectData.XStart); var end=this.GetDataIndexByPoint(selectData.XEnd); if (Math.abs(start-end)<2) return false; selectData.Data=data; if (start>end) { selectData.Start=end; selectData.End=start; } else { selectData.Start=start; selectData.End=end; } return true; } //获取当前的点对应的 画图工具的图形 //data.X data.Y 鼠标位置 返回 data.ChartDrawPicture 数据在画图工具 data.PointIndex 在画图工具对应点索引 this.GetChartDrawPictureByPoint=function(data) { for(var i in this.ChartDrawPicture) { var item =this.ChartDrawPicture[i]; var pointIndex=item.IsPointIn(data.X,data.Y); if (pointIndex===false) continue; if (pointIndex>=0) { data.ChartDrawPicture=item; data.PointIndex=pointIndex; return true; } } return false; } // 保存图片 this.SaveToImage = function (format,colorGB) { if (this.UIElement.width<=0 || this.UIElement.height<=0) return null; if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash) return null; // 数据加载中不能保存 console.log('[JSChartContainer::SaveToImage]', this.UIElement); var clrBG='rgb(255,255,255)'; if (colorGB) clrBG=colorGB; this.Canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height); this.Canvas.fillStyle=clrBG; this.Canvas.fillRect(0,0,this.UIElement.width,this.UIElement.height); //画一个背景色, 不然是一个黑的背景 var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 this.Canvas.lineWidth=pixelTatio; //手机端需要根据分辨率比调整线段宽度 this.Frame.Draw(); //框架 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.IsDynamic && item.IsAnimation==false) item.Draw(); } if (this.Frame.DrawInsideHorizontal) this.Frame.DrawInsideHorizontal(); this.Frame.DrawLock(); for(var i in this.ExtendChartPaint) //动态扩展图形 { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.DrawAfterTitle===false) item.Draw(); } if (this.LastPoint.X!=null || this.LastPoint.Y!=null) { if (this.ChartCorssCursor) //十字光标不画 { this.ChartCorssCursor.LastPoint=this.LastPoint; this.ChartCorssCursor.CursorIndex=this.CursorIndex; } } for(var i in this.TitlePaint) { var item=this.TitlePaint[i]; if (!item.IsDynamic) continue; item.CursorIndex=this.CursorIndex; item.Draw(); } for(var i in this.ExtendChartPaint) //动态扩展图形 { var item=this.ExtendChartPaint[i]; if (item.IsDynamic && item.DrawAfterTitle===true && item.IsAnimation==false) item.Draw(); } if (this.EnableAnimation) { for(var i in this.ExtendChartPaint) //动画 { var item=this.ExtendChartPaint[i]; if (item.IsAnimation===true) item.Draw(); } } for(var i in this.ChartDrawPicture) { var item=this.ChartDrawPicture[i]; item.Draw(); } if (this.CurrentChartDrawPicture && this.CurrentChartDrawPicture.Status!=10) { this.CurrentChartDrawPicture.Draw(); } var dataURL=this.UIElement.toDataURL(format ? format:'image/png', 1.0); console.log('[JSChartContainer::SaveToImage] data= ', dataURL); return dataURL; } this.SaveToImageUrl=function(obj,callback) //obj:{Format: 图片格式, ColorGB: 背景色}, callback:function(bSuccess,obj) { if (!obj) obj={Format:'image/png', ColorGB:'rgb(255,255,255)'}; var imageData=this.SaveToImage(obj.Format, obj.ColorGB); var postData={"Base64":imageData, "BucketName":"downloadcache", "Path":"hqchart/hq_snapshot"}; var url=g_JSChartResource.Domain+'/API/FileUploadForBase64'; JSNetwork.HttpRequest({ url: url, method: "POST", dataType: "json", data: postData, success: function (data) { console.log('[JSChartContainer::SaveToImageUrl] recv data', data); var result={Path:data.relativeurl, Domain:'https://opensourcedownload.zealink.com'}; result.Url=`${result.Domain}/${result.Path}`; if (callback) callback(true,result,''); }, error: function (request) { console.log('[JSChartContainer::SaveToImageUrl] error ', request); if (callback) callback(false,null,'upload failed'); } }); } this.SetLanguage=function(language) { var languageID=null; switch(language) { case 'EN': languageID=JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID; break; case 'CN': languageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; break; default: console.warn(`[JSChartContainer::SetLanguage] language=${language} error`); return; } if (this.LanguageID==languageID) return; this.LanguageID=languageID; if (this.ChartCorssCursor && this.ChartCorssCursor.StringFormatY) this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID; for(var i in this.TitlePaint) { var item=this.TitlePaint[i]; if (item) item.LanguageID=this.LanguageID; } if (this.Frame && this.Frame.SetLanguage) this.Frame.SetLanguage(this.LanguageID); this.Frame.SetSizeChage(true); this.Draw(); } } function GetDevicePixelRatio() { if (typeof(window) =='undefined') return 1; return window.devicePixelRatio || 1; } function IsPhoneWeb() { var userAgentInfo=navigator.userAgent; const Agents =new Array("Android","iPhone","SymbianOS","Windows Phone","iPad","iPod"); for(var v=0;v0) return true; } return false; } function OnKeyDown(e) //键盘事件 { if(this.JSChartContainer && this.JSChartContainer.OnKeyDown) this.JSChartContainer.OnKeyDown(e); } function OnWheel(e) //上下滚动事件 { if(this.JSChartContainer && this.JSChartContainer.OnWheel) this.JSChartContainer.OnWheel(e); } 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 parseInt(value)+0.5; } function ToFixedRect(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 CoordinateInfo() { this.Value; //坐标数据 this.Message=new Array(); //坐标输出文字信息 this.TextColor=g_JSChartResource.FrameSplitTextColor //文字颜色 this.Font=g_JSChartResource.FrameSplitTextFont; //字体 this.LineColor=g_JSChartResource.FrameSplitPen; //线段颜色 this.LineType=1; //线段类型 -1 不画线段 2 虚线 } //边框信息 function ChartBorder() { this.UIElement; //四周间距 this.Left=50; this.Right=80; this.Top=50; this.Bottom=50; this.TitleHeight=24; //标题高度 this.TopSpace=0; this.BottomSpace=0; 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.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.IsLocked=false; //是否上锁 this.LockPaint = null; this.YSpecificMaxMin=null; //指定Y轴最大最小值 this.IsShowBorder = true; //是否显示边框 this.Draw=function() { this.DrawFrame(); this.DrawBorder(); this.SizeChange=false; this.XYSplit=false; } this.DrawFrame=function() { } //画边框 this.DrawBorder=function() { if (!this.IsShowBorder) return; var left=ToFixedPoint(this.ChartBorder.GetLeft()); var top=ToFixedPoint(this.ChartBorder.GetTop()); var right=ToFixedPoint(this.ChartBorder.GetRight()); var bottom=ToFixedPoint(this.ChartBorder.GetBottom()); var width=right-left; var height=bottom-top; //console.log('[IChartFramePainting.DrawBorder] bottom',bottom); this.Canvas.strokeStyle=this.PenBorder; this.Canvas.strokeRect(left,top,width,height); } //画标题背景色 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.GetTopTitle()); 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(true); } } this.CalculateLock=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(false); } } //设施上锁 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; if (lockData.MinWidth>0) this.LockPaint.MinWidth=lockData.MinWidth; } this.GetLockRect=function() { if (!this.IsLocked) return null; if (!this.LockPaint) return null; return this.LockPaint.LockRect; } } //空框架只画边框 function NoneFrame() { this.newMethod=IChartFramePainting; //派生 this.newMethod(); delete this.newMethod; this.Snapshot=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.DataWidth=50*GetDevicePixelRatio(); this.DistanceWidth=10*GetDevicePixelRatio(); this.MinXDistance = 30*GetDevicePixelRatio(); //X轴刻度最小间距 this.MinYDistance=10*GetDevicePixelRatio(); //Y轴刻度最小间距 this.CoordinateType=0; //坐标类型 0=普通坐标 1=反转坐标 this.IsShowYText=[true,true]; //是否显示Y轴坐标坐标 [0=左侧] [1=右侧] this.DrawFrame=function() { if (this.XPointCount>0) { let dInterval=this.ChartBorder.GetWidth()/(6*this.XPointCount); //分6份, 数据4 间距2 this.DistanceWidth=2*dInterval; this.DataWidth=4*dInterval; } this.DrawHorizontal(); this.DrawVertical(); } //isLimit 是否限制在当前坐标下 this.GetYFromData=function(value, isLimit) { if (isLimit===false) { if (this.CoordinateType==1) { var height=this.ChartBorder.GetHeightEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin); return this.ChartBorder.GetTopEx()+height; } else { var height=this.ChartBorder.GetHeightEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin); return this.ChartBorder.GetBottomEx()-height; } } else { if (this.CoordinateType==1) { if(value<=this.HorizontalMin) return this.ChartBorder.GetTopEx(); if(value>=this.HorizontalMax) return this.ChartBorder.GetBottomEx(); var height=this.ChartBorder.GetHeightEx()*(value-this.HorizontalMin)/(this.HorizontalMax-this.HorizontalMin); return this.ChartBorder.GetTopEx()+height; } else { 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.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 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)= bottom - 2) this.Canvas.textBaseline = 'bottom'; else if (y <= top + 2) this.Canvas.textBaseline = 'top'; else this.Canvas.textBaseline = "middle"; //坐标信息 左边 间距小于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="right"; this.Canvas.fillText(item.Message[0],left-2,y); } //坐标信息 右边 间距小于10 不画坐标 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="left"; this.Canvas.fillText(item.Message[1],right+2,y); } yPrev=y; } } //Y刻度画在左边内部 this.DrawInsideHorizontal = function () { if (this.IsHScreen===true) 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 && this.IsShowYText[0]===true) || (borderRight<10 && this.IsShowYText[1]===true) ) { var pixelTatio = GetDevicePixelRatio(); 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 && borderLeft < 10 && this.IsShowYText[0]===true) { if (item.Font != null) this.Canvas.font = item.Font; this.Canvas.fillStyle = item.TextColor; this.Canvas.textAlign = "left"; if (y >= bottom - 2) this.Canvas.textBaseline = 'bottom'; else if (y <= top + 2) this.Canvas.textBaseline = 'top'; 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]}} ; if (!this.IsOverlayMaxMin || !this.IsOverlayMaxMin(textObj)) this.Canvas.fillText(item.Message[0], left + 1*pixelTatio, y); } 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"; if (y >= bottom - 2) this.Canvas.textBaseline = 'bottom'; else if (y <= top + 2) this.Canvas.textBaseline = 'top'; 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]}} ; if (!this.IsOverlayMaxMin || !this.IsOverlayMaxMin(textObj)) this.Canvas.fillText(item.Message[1], right - 1*pixelTatio, y); } yPrev = y; } } } 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(); var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 //console.log('[AverageWidthFrame.DrawVertical] bottom',bottom); var xPrev=null; //上一个坐标x的值 var textRightPrev=null; //上一次刻度输出右边x坐标 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)0) { 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; var textLeft=0; this.Canvas.fillStyle=this.VerticalInfo[i].TextColor; var testWidth=this.Canvas.measureText(this.VerticalInfo[i].Message[0]).width; if (x= this.ChartBorder.GetChartWidth()) { this.Canvas.textAlign = "right"; this.Canvas.textBaseline="top"; textLeft=x-testWidth; } else { this.Canvas.textAlign="center"; this.Canvas.textBaseline="top"; textLeft=x-(testWidth/2); } if (textRightPrev==null || textLeft>textRightPrev) { this.Canvas.fillText(this.VerticalInfo[i].Message[0],x,bottom+1*pixelTatio); textRightPrev=textLeft+testWidth; } } xPrev=x; } } //Y坐标转y轴数值 this.GetYData=function(y) { if (this.CoordinateType==1) //反转坐标 { if (ythis.ChartBorder.GetBottomEx()) return this.HorizontalMax; return (y-this.ChartBorder.GetTopEx())/this.ChartBorder.GetHeightEx()*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin; } else { if (ythis.ChartBorder.GetBottomEx()) return this.HorizontalMin; return (this.ChartBorder.GetBottomEx()-y)/this.ChartBorder.GetHeightEx()*(this.HorizontalMax-this.HorizontalMin)+this.HorizontalMin; } } //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()); } } function MinuteFrame() { this.newMethod=AverageWidthFrame; //派生 this.newMethod(); delete this.newMethod; this.MinuteCount=243; //每天的分钟个数 this.IsBeforeData=false; //是否显示集合竞价 this.BeforeBGColor=g_JSChartResource.Minute.BeforeBGColor; //集合竞价背景 this.DrawFrame=function() { this.SplitXYCoordinate(); if (this.IsBeforeData) this.DrawBeforeDataBG(); this.DrawTitleBG(); this.DrawHorizontal(); this.DrawVertical(); } //画集合竞价背景 this.DrawBeforeDataBG=function() { var left=ToFixedPoint(this.ChartBorder.GetLeft()); var top=ToFixedPoint(this.ChartBorder.GetTopEx()); var right=this.GetXFromIndex(14); var bottom=ToFixedPoint(this.ChartBorder.GetBottom()); var width=right-left; var height=bottom-top; this.Canvas.fillStyle=this.BeforeBGColor; this.Canvas.fillRect(left,top,width,height); } //分割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.GetXFromIndex=function(index) { var count=this.XPointCount-1; 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坐标转x轴数值 this.GetXData=function(x) { var count=this.XPointCount-1; if (count<0) count=0; if (x<=this.ChartBorder.GetLeft()) return 0; if (x>=this.ChartBorder.GetRight()) return count; return (x-this.ChartBorder.GetLeft())*(count*1.0/this.ChartBorder.GetWidth()); } } //走势图 横屏框架 function MinuteHScreenFrame() { this.newMethod=MinuteFrame; //派生 this.newMethod(); delete this.newMethod; 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.DrawBeforeDataBG=function() { var left=ToFixedPoint(this.ChartBorder.GetLeft()); var right=ToFixedPoint(this.ChartBorder.GetRightEx()); var top=ToFixedPoint(this.ChartBorder.GetTop()); var bottom=this.GetXFromIndex(14); var width=right-left; var height=bottom-top; this.Canvas.fillStyle=this.BeforeBGColor; this.Canvas.fillRect(left,top,width,height); } //Y坐标转y轴数值 this.GetYData=function(x) { if (xthis.ChartBorder.GetRightEx()) return this.HorizontalMax; return (x-this.ChartBorder.GetLeft())/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; return (y-this.ChartBorder.GetTop())*(this.XPointCount*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)= 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"; 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"; 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.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.ToolbarID=Guid(); //工具条Div id this.ModifyIndex=true; //是否显示'改参数'菜单 this.ChangeIndex=true; //是否显示'换指标'菜单 this.CloseIndex=true; //是否显示'关闭指标窗口'菜单 this.OverlayIndex=false; //是否显示叠加指标 this.ModifyIndexEvent; //改参数 点击事件 this.ChangeIndexEvent; //换指标 点击事件 this.LastCalculateStatus={ Width:0, XPointCount:0 }; //最后一次计算宽度的状态 this.CustomHorizontalInfo=[]; this.DrawToolbar=function() { if (!this.ChartBorder.UIElement) return; var divToolbar=document.getElementById(this.ToolbarID); if (!divToolbar) { divToolbar=document.createElement("div"); divToolbar.className='klineframe-toolbar'; divToolbar.id=this.ToolbarID; //为divToolbar添加属性identify divToolbar.setAttribute("identify",this.Identify.toString()); this.ChartBorder.UIElement.parentNode.appendChild(divToolbar); } if (!this.ModifyIndex && !this.ChangeIndex && !this.OverlayIndex) { divToolbar.style.display='none'; return; } //使用外城div尺寸 画图尺寸是被放大的 var pixelTatio = GetDevicePixelRatio(); var chartWidth=parseInt(this.ChartBorder.UIElement.parentElement.style.width.replace("px","")); var chartHeight=parseInt(this.ChartBorder.UIElement.parentElement.style.height.replace("px","")); //console.log('[KLineFrame::DrawToolbar] ',chartWidth,chartHeight,pixelTatio); var toolbarWidth=100; var toolbarHeight=this.ChartBorder.GetTitleHeight(); var left=chartWidth-(this.ChartBorder.Right/pixelTatio)-toolbarWidth; var top=this.ChartBorder.GetTop()/pixelTatio; var spanIcon = "" + "" + ""; if (this.Identify!==0 && this.CloseIndex) //第1个窗口不能关闭 { const spanCloseIcon=""; spanIcon+=spanCloseIcon; } //var scrollPos=GetScrollPosition(); //left = left+scrollPos.Left; //top = top+scrollPos.Top; divToolbar.style.left = left + "px"; divToolbar.style.top = top + "px"; divToolbar.style.width=toolbarWidth+"px"; //宽度先不调整吧 divToolbar.style.height=(toolbarHeight/pixelTatio)+'px'; //只调整高度 divToolbar.innerHTML=spanIcon; var chart=this.ChartBorder.UIElement.JSChartContainer; var identify=this.Identify; if (!this.ModifyIndex) //隐藏'改参数' $("#"+divToolbar.id+" .index_param").hide(); else if (typeof(this.ModifyIndexEvent)=='function') //绑定点击事件 $("#"+divToolbar.id+" .index_param").click( { Chart:this.ChartBorder.UIElement.JSChartContainer, Identify:this.Identify },this.ModifyIndexEvent); if (!this.ChangeIndex) //隐藏'换指标' { $("#"+divToolbar.id+" .index_change").hide(); } else if (typeof(this.ChangeIndexEvent)=='function') { $("#"+divToolbar.id+" .index_change").click( { Chart:this.ChartBorder.UIElement.JSChartContainer, Identify:this.Identify, IsOverlay:false },this.ChangeIndexEvent); } if (!this.OverlayIndex) { $("#"+divToolbar.id+" .index_overlay").hide(); } else { $("#"+divToolbar.id+" .index_overlay").click( { Chart:this.ChartBorder.UIElement.JSChartContainer, Identify:this.Identify, IsOverlay:true },this.ChangeIndexEvent); } $("#"+divToolbar.id+" .index_close").click( { Chart:this.ChartBorder.UIElement.JSChartContainer, Identify:this.Identify }, function(event) { var hqChart=event.data.Chart; var id=event.data.Identify; hqChart.RemoveIndexWindow(id); }); divToolbar.style.display = "block"; } this.ClearToolbar=function() { var divToolbar=document.getElementById(this.ToolbarID); if (!divToolbar) return; this.ChartBorder.UIElement.parentNode.removeChild(divToolbar); } this.DrawFrame=function() { this.SplitXYCoordinate(); if (this.SizeChange==true) this.CalculateDataWidth(); this.DrawTitleBG(); this.DrawHorizontal(); this.DrawVertical(); if (this.SizeChange==true) this.DrawToolbar(); //大小变动才画工具条 } //isLimit 是否限制在当前屏坐标下 this.GetXFromIndex=function(index,isLimit) { if (isLimit===false) { if (index>=0) { var offset=this.ChartBorder.GetLeft()+2+this.DistanceWidth/2+this.DataWidth/2; for(var i=1;i<=index;++i) { offset+=this.DistanceWidth+this.DataWidth; } } else { var offset=this.ChartBorder.GetLeft()+2+this.DistanceWidth/2+this.DataWidth/2; var absIndex=Math.abs(index); for(var i=0;i 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坐标转x轴数值 this.GetXData=function(x) { if (x<=this.ChartBorder.GetLeft()) return 0; if (x>=this.ChartBorder.GetRight()) return this.XPointCount; var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var distanceWidth=this.DistanceWidth; var dataWidth=this.DataWidth; var index=0; var xPoint=left+dataWidth+distanceWidth; while(xPointx) break; xPoint+=(dataWidth+distanceWidth); ++index; } //var test=(x-this.ChartBorder.GetLeft())*(this.XPointCount*1.0/this.ChartBorder.GetWidth()); return index; } //计算数据宽度 this.CalculateDataWidth=function() { if (this.XPointCount<2) return; //console.log(`[KLineFrame::CalculateDataWidth] ZoomIndex=${this.ZoomIndex}, XPointCount=${this.XPointCount}, DataWidth=${this.DataWidth}, DistanceWidth=${this.DistanceWidth}`); var width=this.ChartBorder.GetWidth()-4; if (this.ZoomIndex>0 && this.LastCalculateStatus.Width==width && this.LastCalculateStatus.XPointCount==this.XPointCount) //宽度没变 尝试使用原来的柱子宽度 { if ((this.DataWidth + this.DistanceWidth) * this.XPointCount <= width) //当前的柱子宽度够用 就不调整了 return; } this.LastCalculateStatus.Width=width; this.LastCalculateStatus.XPointCount=this.XPointCount; for(var i=0;i width) { this.DistanceWidth -= 0.01; break; } this.DistanceWidth += 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; //刻度文字宽度 if (obj.Text.TextAlign==='right') obj.X-=textWidth; 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) //最大值X 坐标不在 刻度文字范围内 { 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) { 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.ChartBorder.GetWidth()-4; 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 lastDataIndex = this.Data.DataOffset + this.XPointCount - 1; //最右边的数据索引 var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index; if (lastDataIndex>this.Data.Data.length) lastDataIndex=this.Data.Data.length-1; //console.log(`[KLineFrame::ZoomUp] old status. XPointCount=${this.XPointCount} ZoomIndex=${this.ZoomIndex}`); --this.ZoomIndex; var xPointCount=this.CalculateCount(this.ZoomIndex); this.XPointCount=xPointCount; this.DataWidth = ZOOM_SEED[this.ZoomIndex][0]; this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1]; this.TrimKLineDataWidth(this.ChartBorder.GetWidth()); this.LastCalculateStatus.XPointCount=this.XPointCount; //console.log(`[KLineFrame::ZoomUp] new status. XPointCount=${this.XPointCount} ZoomIndex=${this.ZoomIndex}`); if (lastDataIndex>=this.Data.Data.length) { this.Data.DataOffset=this.Data.Data.length-this.XPointCount-2; cursorIndex.Index=this.Data.Data.length-this.Data.DataOffset-1; } else { if (lastDataIndex=ZOOM_SEED.length) return false; if (this.Data.DataOffset<0) return false; var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1; //最右边的数据索引 if (lastDataIndex>=this.Data.Data.length) lastDataIndex=this.Data.Data.length-1; //console.log(`[KLineFrame::ZoomDown] old status. XPointCount=${this.XPointCount} ZoomIndex=${this.ZoomIndex}`); var xPointCount=this.CalculateCount(this.ZoomIndex+1); var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index; ++this.ZoomIndex; this.XPointCount=xPointCount; this.DataWidth = ZOOM_SEED[this.ZoomIndex][0]; this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1]; this.TrimKLineDataWidth(this.ChartBorder.GetWidth()); this.LastCalculateStatus.XPointCount=this.XPointCount; //console.log(`[KLineFrame::ZoomDown] new status. XPointCount=${this.XPointCount} ZoomIndex=${this.ZoomIndex}`); if (lastDataIndex-xPointCount+1<0) this.Data.DataOffset=0; else this.Data.DataOffset = lastDataIndex - this.XPointCount+1; cursorIndex.Index=lastCursorIndex-this.Data.DataOffset; return true; } this.DrawCustomHorizontal=function() //Y轴刻度定制显示 { for(var i in this.CustomHorizontalInfo) { var item=this.CustomHorizontalInfo[i]; switch(item.Type) { case 0: this.DrawLatestPrice(item); break; } } } this.DrawLatestPrice=function(item) //显示最新价格 { if (this.IsHScreen===true) return; //横屏不画 if (!item.Message[1] && !item.Message[0]) return; if (item.Value>this.HorizontalMax || item.Value=0; --i) //从上往下画分割线 { var item=this.HorizontalInfo[i]; var y=this.GetYFromData(item.Value); if (y!=null && Math.abs(y-yPrev)= bottom - 2) this.Canvas.textBaseline = 'bottom'; else if (y <= top + 2) this.Canvas.textBaseline = 'top'; else this.Canvas.textBaseline = "middle"; this.Canvas.strokeStyle=this.PenBorder; this.Canvas.beginPath(); this.Canvas.moveTo(right-2,ToFixedPoint(y)); this.Canvas.lineTo(right,ToFixedPoint(y)); this.Canvas.stroke(); //坐标信息 右边 间距小于10 不画坐标 if (item.Message[1]!=null && borderRight>10) { if (item.Font!=null) this.Canvas.font=item.Font; this.Canvas.fillStyle=item.TextColor; this.Canvas.textAlign="left"; this.Canvas.fillText(item.Message[1],right+2,y); } yPrev=y; } } //画X轴 this.DrawVertical=function() { var top=this.ChartBorder.GetTopEx(); //var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var bottom=this.ChartBorder.GetBottomEx(); right+=this.RightOffset; this.Canvas.strokeStyle=this.PenBorder; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(right),ToFixedPoint(top)); this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(bottom)); this.Canvas.stroke(); } } //K线横屏框架 function KLineHScreenFrame() { this.newMethod=KLineFrame; //派生 this.newMethod(); delete this.newMethod; this.IsHScreen=true; //是否是横屏 //画标题背景色 this.DrawTitleBG=function() { if (this.ChartBorder.TitleHeight<=0) return; var left=ToFixedPoint(this.ChartBorder.GetRightTitle()); 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.DrawToolbar=function() { return; } 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 yPrev=null; //上一个坐标y的值 var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 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; //两个坐标在近了 就不画了 this.Canvas.strokeStyle=item.LineColor; 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*pixelTatio) { 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*pixelTatio) { 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()+2+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; 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 (xthis.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; return (y-this.ChartBorder.GetTop())*(this.XPointCount*1.0/this.ChartBorder.GetHeight()); } //计算数据宽度 this.CalculateDataWidth=function() { if (this.XPointCount<2) return; var width=this.ChartBorder.GetHeight()-4; for(var i=0;ithis.Data.Data.length) lastDataIndex=this.Data.Data.length-1; --this.ZoomIndex; var xPointCount=this.CalculateCount(this.ZoomIndex); this.XPointCount=xPointCount; this.DataWidth = ZOOM_SEED[this.ZoomIndex][0]; this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1]; this.TrimKLineDataWidth(this.ChartBorder.GetHeight()); if (lastDataIndex>=this.Data.Data.length) { this.Data.DataOffset=this.Data.Data.length-this.XPointCount-2; cursorIndex.Index=this.Data.Data.length-this.Data.DataOffset-1; } else { if (lastDataIndex=ZOOM_SEED.length) return false; if (this.Data.DataOffset<0) return false; var lastDataIndex = this.Data.DataOffset + this.XPointCount - 1; //最右边的数据索引 if (lastDataIndex>=this.Data.Data.length) lastDataIndex=this.Data.Data.length-1; var xPointCount=this.CalculateCount(this.ZoomIndex+1); var lastCursorIndex=this.Data.DataOffset + cursorIndex.Index; ++this.ZoomIndex; this.XPointCount=xPointCount; this.DataWidth = ZOOM_SEED[this.ZoomIndex][0]; this.DistanceWidth = ZOOM_SEED[this.ZoomIndex][1]; this.TrimKLineDataWidth(this.ChartBorder.GetHeight()); if (lastDataIndex-xPointCount+1<0) this.Data.DataOffset=0; else this.Data.DataOffset = lastDataIndex - this.XPointCount+1; cursorIndex.Index=lastCursorIndex-this.Data.DataOffset; return true; } } function OverlayKLineHScreenFrame() { this.newMethod=KLineHScreenFrame; //派生 this.newMethod(); delete this.newMethod; this.MainFrame=null; //主框架 this.RightOffset=50; this.PenBorder=g_JSChartResource.OverlayFrame.BolderPen; //'rgb(0,0,0)' this.IsShow=true; //坐标是否显示 this.Title=null; this.TitleColor=g_JSChartResource.OverlayFrame.TitleColor; this.TitleFont=g_JSChartResource.OverlayFrame.TitleFont; this.Draw=function() { this.SplitXYCoordinate(); if (this.IsShow) { this.DrawVertical(); this.DrawHorizontal(); this.DrawTitle(); } this.SizeChange=false; this.XYSplit=false; } this.DrawTitle=function() //画标题 { /* if (!this.Title) return; var top = this.ChartBorder.GetTopTitle(); var bottom = this.ChartBorder.GetBottom(); var right=this.ChartBorder.GetRight(); right+=this.RightOffset; this.Canvas.fillStyle=this.TitleColor; this.Canvas.font=this.TitleFont; this.Canvas.textAlign="center"; this.Canvas.textBaseline="top"; var xText=right-2,yText=top+(bottom-top)/2; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(this.Title, 0, 0); this.Canvas.restore(); */ } //分割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轴一致 所以不用计算 } //画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; right+=this.RightOffset; 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)= bottom - 2) this.Canvas.textBaseline = 'bottom'; else if (y <= top + 2) this.Canvas.textBaseline = 'top'; else this.Canvas.textBaseline = "middle"; this.Canvas.strokeStyle=this.PenBorder; this.Canvas.beginPath(); this.Canvas.moveTo(right-2,ToFixedPoint(y)); this.Canvas.lineTo(right,ToFixedPoint(y)); this.Canvas.stroke(); //坐标信息 右边 间距小于10 不画坐标 if (item.Message[1]!=null && borderRight>10) { if (item.Font!=null) this.Canvas.font=item.Font; this.Canvas.fillStyle=item.TextColor; this.Canvas.textAlign="left"; this.Canvas.fillText(item.Message[1],right+2,y); } yPrev=y; } */ } //画X轴 this.DrawVertical=function() { /* var top=this.ChartBorder.GetTopEx(); //var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var bottom=this.ChartBorder.GetBottomEx(); right+=this.RightOffset; this.Canvas.strokeStyle=this.PenBorder; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(right),ToFixedPoint(top)); this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(bottom)); this.Canvas.stroke(); */ } } function SubFrameItem() { this.Frame; this.Height; this.OverlayIndex=[]; //叠加指标 this.Interval=60; //子坐标间间距 } function OverlayIndexItem() { this.Frame; this.ChartPaint=[]; this.Identify=Guid(); this.Scprit; //脚本 this.UpdateFrameMaxMin=function() //调整坐标最大 最小值 { var value={Max:null, Min:null} if (this.Frame.YSpecificMaxMin) //固定坐标 { value.Max=this.Frame.YSpecificMaxMin.Max; value.Min=this.Frame.YSpecificMaxMin.Min; } else { for(var i in this.ChartPaint) { var paint=this.ChartPaint[i]; var range=paint.GetMaxMin(); if (value.Max==null || value.Maxrange.Min) value.Min=range.Min } } if (value.Max!=null && value.Min!=null) { this.Frame.HorizontalMax=value.Max; this.Frame.HorizontalMin=value.Min; this.Frame.XYSplit=true; } } } //行情框架 function HQTradeFrame() { this.SubFrame=new Array(); //SubFrameItem 数组 this.SizeChange=true; //大小是否改变 this.ChartBorder; this.Canvas; //画布 this.ScreenImageData; //截图 this.Data; //主数据 this.Position; //画布的位置 this.SizeChange=true; 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.CalculateChartBorder2=function() //计算每个子框架的边框信息(思维导图用) { if (this.SubFrame.length<=0) return; var top=this.ChartBorder.Top; var bottom=this.ChartBorder.Bottom; var height=this.ChartBorder.GetHeight(); var totalHeight=0; for(var i in this.SubFrame) { var item=this.SubFrame[i]; totalHeight+=item.Height; } var tempHeight=0; 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; item.Frame.ChartBorder.X=this.ChartBorder.X; item.Frame.ChartBorder.Y=this.ChartBorder.Y; item.Frame.ChartBorder.Width=this.ChartBorder.Width; item.Frame.ChartBorder.Height=this.ChartBorder.Height; var frameHeight=height*(item.Height/totalHeight); tempHeight+=frameHeight; bottom=this.ChartBorder.Bottom+(height-tempHeight); item.Frame.ChartBorder.Bottom=bottom; top+=frameHeight; } } this.Draw=function() { if (this.SizeChange===true) this.CalculateChartBorder(); for(var i in this.SubFrame) { var item=this.SubFrame[i]; item.Frame.Draw(); var rightOffset=item.Interval; for(var j in item.OverlayIndex) { var overlayItem=item.OverlayIndex[j]; //把主坐标部分设置给子坐标下来 overlayItem.Frame.DataWidth=item.Frame.DataWidth; overlayItem.Frame.DistanceWidth=item.Frame.DistanceWidth; overlayItem.Frame.XPointCount=item.Frame.XPointCount; if (overlayItem.ChartPaint.length>0 && overlayItem.Frame.IsShow) { overlayItem.Frame.RightOffset=rightOffset; overlayItem.Frame.Draw(); rightOffset+=item.Interval; } } } this.SizeChange=false; } this.DrawOveraly=function() { for(var i in this.SubFrame) { var item=this.SubFrame[i]; for(var j in item.OverlayIndex) { var overlayItem=item.OverlayIndex[j]; for(var k in overlayItem.ChartPaint) { if (overlayItem.ChartPaint[k].IsShow) overlayItem.ChartPaint[k].Draw(); } } } } this.DrawLock=function() { for (var i in this.SubFrame) { var item = this.SubFrame[i]; item.Frame.DrawLock(); } } this.CalculateLock=function() { for (var i in this.SubFrame) { var item = this.SubFrame[i]; item.Frame.CalculateLock(); } } this.DrawInsideHorizontal = function () { for (var i in this.SubFrame) { var item = this.SubFrame[i]; if (item.Frame.DrawInsideHorizontal) item.Frame.DrawInsideHorizontal(); } } this.DrawCustomHorizontal=function() //定制坐标 { for (var i in this.SubFrame) { var item = this.SubFrame[i]; if (item.Frame.DrawCustomHorizontal) item.Frame.DrawCustomHorizontal(); } } this.SetSizeChage=function(sizeChange) { this.SizeChange=sizeChange; for(var i in this.SubFrame) { var item=this.SubFrame[i]; item.Frame.SizeChange=sizeChange; for(var j in item.OverlayIndex) { var overlayItem=item.OverlayIndex[j]; if (overlayItem.Frame) overlayItem.Frame.SizeChange=sizeChange; } } //画布的位置 if (this.ChartBorder.UIElement) { this.Position={ X:this.ChartBorder.UIElement.offsetLeft, Y:this.ChartBorder.UIElement.offsetTop, W:this.ChartBorder.UIElement.clientWidth, H:this.ChartBorder.UIElement.clientHeight }; } } //图形快照 this.Snapshot=function() { this.ScreenImageData=this.Canvas.getImageData(0,0,this.ChartBorder.GetChartWidth(),this.ChartBorder.GetChartHeight()); } this.GetXData=function(x) { return this.SubFrame[0].Frame.GetXData(x); } this.GetYData=function(y,outObject) //outObject 可以保存返回的额外数据 { var frame; for(var i in this.SubFrame) { var item=this.SubFrame[i]; var left=item.Frame.ChartBorder.GetLeft(); var top=item.Frame.ChartBorder.GetTopEx(); var width=item.Frame.ChartBorder.GetWidth(); var height=item.Frame.ChartBorder.GetHeightEx(); item.Frame.Canvas.beginPath(); item.Frame.Canvas.rect(left,top,width,height); if (item.Frame.Canvas.isPointInPath(left,y)) { frame=item.Frame; if (outObject) outObject.FrameID=parseInt(i); //转成整形 break; } } if (frame!=null) return frame.GetYData(y); } this.PtInFrame=function(x,y) //鼠标哪个指标窗口 { for(var i in this.SubFrame) { var item=this.SubFrame[i]; var left=item.Frame.ChartBorder.GetLeft(); var top=item.Frame.ChartBorder.GetTop(); var width=item.Frame.ChartBorder.GetWidth(); var height=item.Frame.ChartBorder.GetHeight(); item.Frame.Canvas.beginPath(); item.Frame.Canvas.rect(left,top,width,height); if (item.Frame.Canvas.isPointInPath(x,y)) { return parseInt(i); //转成整形 } } return -1; } this.GetXFromIndex=function(index) { return this.SubFrame[0].Frame.GetXFromIndex(index); } this.GetYFromData=function(value) { return this.SubFrame[0].Frame.GetYFromData(value); } this.ZoomUp=function(cursorIndex) { var result=this.SubFrame[0].Frame.ZoomUp(cursorIndex); var mainFrame=this.SubFrame[0].Frame; for(var i=0;i0) //第1个窗口主坐标已经算好了 { item.Frame.XPointCount= mainFrame.XPointCount; item.Frame.ZoomIndex= mainFrame.ZoomIndex; item.Frame.DataWidth= mainFrame.DataWidth; item.Frame.DistanceWidth= mainFrame.DistanceWidth; item.Frame.LastCalculateStatus.Width=mainFrame.LastCalculateStatus.Width; item.Frame.LastCalculateStatus.XPointCount=mainFrame.LastCalculateStatus.XPointCount; } for(var j in item.OverlayIndex) { var overlayItem=this.SubFrame[i].OverlayIndex[j]; overlayItem.Frame.XPointCount= mainFrame.XPointCount; overlayItem.Frame.ZoomIndex= mainFrame.ZoomIndex; overlayItem.Frame.DataWidth= mainFrame.DataWidth; overlayItem.Frame.DistanceWidth= mainFrame.DistanceWidth; overlayItem.Frame.LastCalculateStatus.Width=mainFrame.LastCalculateStatus.Width; overlayItem.Frame.LastCalculateStatus.XPointCount=mainFrame.LastCalculateStatus.XPointCount; } } return result; } this.ZoomDown=function(cursorIndex) { var result=this.SubFrame[0].Frame.ZoomDown(cursorIndex); var mainFrame=this.SubFrame[0].Frame; for(var i=0;i0) //第1个窗口主坐标已经算好了 { item.Frame.XPointCount= mainFrame.XPointCount; item.Frame.ZoomIndex= mainFrame.ZoomIndex; item.Frame.DataWidth= mainFrame.DataWidth; item.Frame.DistanceWidth= mainFrame.DistanceWidth; item.Frame.LastCalculateStatus.Width=mainFrame.LastCalculateStatus.Width; item.Frame.LastCalculateStatus.XPointCount=mainFrame.LastCalculateStatus.XPointCount; } for(var j in item.OverlayIndex) { var overlayItem=this.SubFrame[i].OverlayIndex[j]; overlayItem.Frame.XPointCount= mainFrame.XPointCount; overlayItem.Frame.ZoomIndex= mainFrame.ZoomIndex; overlayItem.Frame.DataWidth= mainFrame.DataWidth; overlayItem.Frame.DistanceWidth= mainFrame.DistanceWidth; overlayItem.Frame.LastCalculateStatus.Width=mainFrame.LastCalculateStatus.Width; overlayItem.Frame.LastCalculateStatus.XPointCount=mainFrame.LastCalculateStatus.XPointCount; } } return result; } //设置重新计算刻度坐标 this.ResetXYSplit=function() { for(let i in this.SubFrame) { this.SubFrame[i].Frame.XYSplit=true; } } this.SetLanguage=function(languageID) { for(let i in this.SubFrame) { var item=this.SubFrame[i]; if (item && item.Frame ) { if (item.Frame.YSplitOperator) item.Frame.YSplitOperator.LanguageID=languageID; if (item.Frame.XSplitOperator) item.Frame.XSplitOperator.LanguageID=languageID; } } } } //行情框架横屏 function HQTradeHScreenFrame() { this.newMethod=HQTradeFrame; //派生 this.newMethod(); delete this.newMethod; this.IsHScreen=true; //是否是横屏 this.CalculateChartBorder=function() //计算每个子框架的边框信息 { if (this.SubFrame.length<=0) return; var right=this.ChartBorder.Right; var left=this.ChartBorder.GetRight(); var width=this.ChartBorder.GetWidth(); 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=this.ChartBorder.Top; item.Frame.ChartBorder.Bottom=this.ChartBorder.Bottom; var frameWidth=width*(item.Height/totalHeight); item.Frame.ChartBorder.Right=right; item.Frame.ChartBorder.Left=left-frameWidth; right+=frameWidth; left-=frameWidth; } } this.GetYData=function(x,outObject) { var frame; for(var i in this.SubFrame) { var item=this.SubFrame[i]; var left=item.Frame.ChartBorder.GetLeftEx(); var top=item.Frame.ChartBorder.GetTop(); var width=item.Frame.ChartBorder.GetWidthEx(); var height=item.Frame.ChartBorder.GetHeight(); item.Frame.Canvas.beginPath(); item.Frame.Canvas.rect(left,top,width,height); if (item.Frame.Canvas.isPointInPath(x,top)) { frame=item.Frame; if (outObject) outObject.FrameID=i; break; } } if (frame!=null) return frame.GetYData(x); } } function SimpleChartFrame() { this.newMethod=AverageWidthFrame; //派生 this.newMethod(); delete this.newMethod; this.ScreenImageData; //截图 this.Position; //画布的位置 this.DrawFrame=function() { if (this.XPointCount>0) { let dInterval=this.ChartBorder.GetWidth()/(6*this.XPointCount); //分6份, 数据4 间距2 this.DistanceWidth=2*dInterval; this.DataWidth=4*dInterval; } 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(); } //图形快照 this.Snapshot=function() { this.ScreenImageData=this.Canvas.getImageData(0,0,this.ChartBorder.GetChartWidth(),this.ChartBorder.GetChartHeight()); } 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 }; } } //历史K线数据 function HistoryData() { this.Date; this.YClose; this.Open; this.Close; this.High; this.Low; this.Vol; this.Amount; this.Time; this.FlowCapital=0; //流通股本 //指数才有的数据 this.Stop; //停牌家数 this.Up; //上涨 this.Down; //下跌 this.Unchanged; //平盘 } //数据复制 HistoryData.Copy=function(data) { var newData=new HistoryData(); newData.Date=data.Date; newData.YClose=data.YClose; newData.Open=data.Open; newData.Close=data.Close; newData.High=data.High; newData.Low=data.Low; newData.Vol=data.Vol; newData.Amount=data.Amount; newData.Time=data.Time; newData.FlowCapital=data.FlowCapital; newData.Stop=data.Stop; newData.Up=data.Up; newData.Down=data.Down; newData.Unchanged=data.Unchanged; return newData; } //把数据 src 复制到 dest中 HistoryData.CopyTo=function(dest,src) { dest.Date=src.Date; dest.YClose=src.YClose; dest.Open=src.Open; dest.Close=src.Close; dest.High=src.High; dest.Low=src.Low; dest.Vol=src.Vol; dest.Amount=src.Amount; dest.Time=src.Time; dest.FlowCapital=src.FlowCapital; dest.Stop=src.Stop; dest.Up=src.Up; dest.Down=src.Down; dest.Unchanged=src.Unchanged; } //数据复权拷贝 HistoryData.CopyRight=function(data,seed) { var newData=new HistoryData(); newData.Date=data.Date; newData.YClose=data.YClose*seed; newData.Open=data.Open*seed; newData.Close=data.Close*seed; newData.High=data.High*seed; newData.Low=data.Low*seed; newData.Vol=data.Vol; newData.Amount=data.Amount; newData.FlowCapital=data.FlowCapital; return newData; } function MinuteData() { this.Close; this.Open; this.High; this.Low; this.Vol; this.Amount; this.DateTime; this.Increase; this.Risefall; this.AvPrice; this.Lead=null; this.Time; this.Date; } //单指标数据 function SingleData() { this.Date; //日期 this.Time; //时间 this.Value; //数据 (可以是一个数组) } var KLINE_INFO_TYPE= { INVESTOR:1, //互动易 ANNOUNCEMENT:2, //公告 PFORECAST:3, //业绩预告 ANNOUNCEMENT_QUARTER_1:4, //一季度报 ANNOUNCEMENT_QUARTER_2:5, //半年报 ANNOUNCEMENT_QUARTER_3:6, //2季度报 ANNOUNCEMENT_QUARTER_4:7, //年报 RESEARCH:8, //调研 BLOCKTRADING:9, //大宗交易 TRADEDETAIL:10 //龙虎榜 } function KLineInfoData() { this.ID; this.Date; this.Title; this.InfoType; this.ExtendData; //扩展数据 } function DataPlus () { }; //外部数据计算方法接口 DataPlus.GetMinutePeriodData=null; /* DataPlus.GetMinutePeriodData=function(period,data,self) { } */ function ChartData() { this.Data=new Array(); this.DataOffset=0; //数据偏移 this.Period=0; //周期 0 日线 1 周线 2 月线 3年线 this.Right=0; //复权 0 不复权 1 前复权 2 后复权 this.Symbol; //股票代码 this.Data2=new Array(); //第1组数据 走势图:历史分钟数据 this.GetCloseMA=function(dayCount) { var result=new Array(); for (var i = 0, len = this.Data.length; i < len; i++) { if (i < dayCount) { result[i]=null; continue; } var sum = 0; for (var j = 0; j < dayCount; j++) { sum += this.Data[i - j].Close; } result[i]=sum / dayCount; } return result; } this.GetVolMA=function(dayCount) { var result=new Array(); for (var i = 0, len = this.Data.length; i < len; i++) { if (i < dayCount) { result[i]=null; continue; } var sum = 0; for (var j = 0; j < dayCount; j++) { sum += this.Data[i - j].Vol; } result[i]=sum / dayCount; } return result; } this.GetAmountMA=function(dayCount) { var result=new Array(); for (var i = 0, len = this.Data.length; i < len; i++) { if (i < dayCount) { result[i]=null; continue; } var sum = 0; for (var j = 0; j < dayCount; j++) { sum += this.Data[i - j].Amount; } result[i]=sum / dayCount; } return result; } //获取收盘价 this.GetClose=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Close; } return result; } this.GetYClose=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].YClose; } return result; } this.GetHigh=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].High; } return result; } this.GetLow=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Low; } return result; } this.GetOpen=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Open; } return result; } this.GetVol=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Vol; } return result; } this.GetAmount=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Amount; } return result; } this.GetLead=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Lead; } return result; } this.GetDate=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Date; } return result; } this.GetTime=function() { var result=new Array(); for(var i in this.Data) { result[i]=this.Data[i].Time; } return result; } this.GetUp=function() //上涨家数 { var result=[]; for(var i in this.Data) { result[i]=this.Data[i].Up; } return result; } this.GetDown=function() //下跌家数 { var result=[]; for(var i in this.Data) { result[i]=this.Data[i].Down; } return result; } this.GetYear=function() { var result=new Array(); for(var i in this.Data) { result[i]=parseInt(this.Data[i].Date/10000); } return result; } this.GetMonth=function() { var result=new Array(); for(var i in this.Data) { result[i]=parseInt(this.Data[i].Date%10000/100); } return result; } //计算分钟 this.GetMinutePeriodData=function(period) { if (DataPlus.GetMinutePeriodData) return DataPlus.GetMinutePeriodData(period,this.Data,this); var result = new Array(); var periodDataCount = 5; if (period == 5) periodDataCount = 5; else if (period == 6) periodDataCount = 15; else if (period == 7) periodDataCount = 30; else if (period == 8) periodDataCount = 60; else if (period==11) periodDataCount=120; else if (period==12) periodDataCount=240; else if (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END) { periodDataCount=period-CUSTOM_MINUTE_PERIOD_START; return this.GetMinuteCustomPeriodData(periodDataCount); } else return this.Data; var bFirstPeriodData = false; var newData = null; var preTime=null; //上一次的计算时间 for (var i = 0; i < this.Data.length; ) { bFirstPeriodData = true; for (var j = 0; j < periodDataCount && i < this.Data.length; ++i) { if (bFirstPeriodData) { newData = new HistoryData(); result.push(newData); bFirstPeriodData = false; } var minData = this.Data[i]; if (minData == null) { ++j; continue; } if (minData.Time==925 && (preTime==null || preTime!=924)) //9:25, 9:30 不连续就不算个数 { } else if (minData.Time == 930 && (preTime==null || preTime!=929) ) { } else if (minData.Time == 1300 && (preTime==null || preTime!=1259) ) //1点的数据 如果不是连续的 就不算个数 { } else ++j; newData.Date = minData.Date; newData.Time = minData.Time; preTime=newData.Time; if (minData.Open==null || minData.Close==null) continue; if (newData.Open==null || newData.Close==null) { newData.Open=minData.Open; newData.High=minData.High; newData.Low=minData.Low; newData.YClose=minData.YClose; newData.Close=minData.Close; newData.Vol=minData.Vol; newData.Amount=minData.Amount; newData.FlowCapital=minData.FlowCapital; } else { if (newData.HighminData.Low) newData.Low=minData.Low; newData.Close=minData.Close; newData.Vol+=minData.Vol; if (minData.Amount!=null) newData.Amount+=minData.Amount; newData.FlowCapital=minData.FlowCapital; } if (i+1 < this.Data.length) //判断下一个数据是否是不同日期的 { var nextItem=this.Data[i+1]; if (nextItem && nextItem.Date!=minData.Date) //不同日期的, 周期结束 { ++i; break; } } } } return result; } //自定义分钟 this.GetMinuteCustomPeriodData=function(count) { var result = new Array(); var periodDataCount = count; var bFirstPeriodData = false; var newData = null; for (var i = 0; i < this.Data.length; ) { bFirstPeriodData = true; for (var j = 0; j < periodDataCount && i < this.Data.length; ++i, ++j) { if (bFirstPeriodData) { newData = new HistoryData(); result.push(newData); bFirstPeriodData = false; } var minData = this.Data[i]; if (minData == null) continue; newData.Date = minData.Date; newData.Time = minData.Time; if (minData.Open==null || minData.Close==null) continue; if (newData.Open==null || newData.Close==null) { newData.Open=minData.Open; newData.High=minData.High; newData.Low=minData.Low; newData.YClose=minData.YClose; newData.Close=minData.Close; newData.Vol=minData.Vol; newData.Amount=minData.Amount; newData.FlowCapital=minData.FlowCapital; } else { if (newData.HighminData.Low) newData.Low=minData.Low; newData.Close=minData.Close; newData.Vol+=minData.Vol; if (minData.Amount!=null) newData.Amount+=minData.Amount; //null数据不相加 newData.FlowCapital=minData.FlowCapital; } } } return result; } //计算周,月,年 this.GetDayPeriodData=function(period) { if (period>CUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_END) return this.GetDayCustomPeriodData(period-CUSTOM_DAY_PERIOD_START); var isBit=MARKET_SUFFIX_NAME.IsBIT(this.Symbol); var result=new Array(); var index=0; var startDate=0; var newData=null; for(var i in this.Data) { var isNewData=false; var dayData=this.Data[i]; switch(period) { case 1: //周线 if (isBit) //数字货币全年的 { var sundayDate=ChartData.GetSunday(dayData.Date); if (sundayDate!=startDate) { isNewData=true; startDate=sundayDate; } } else { var fridayDate=ChartData.GetFirday(dayData.Date); if (fridayDate!=startDate) { isNewData=true; startDate=fridayDate; } } break; case 2: //月线 if (parseInt(dayData.Date/100)!=parseInt(startDate/100)) { isNewData=true; startDate=dayData.Date; } break; case 3: //年线 if (parseInt(dayData.Date/10000)!=parseInt(startDate/10000)) { isNewData=true; startDate=dayData.Date; } break; case 9: //季线 var now=ChartData.GetQuarter(dayData.Date); now=parseInt(dayData.Date/10000)*10+now; var last=ChartData.GetQuarter(startDate); last=parseInt(startDate/10000)*10+last; if (now!=last) { isNewData=true; startDate=dayData.Date; } break; } if (isNewData) { newData=new HistoryData(); newData.Date=dayData.Date; result.push(newData); if (dayData.Open==null || dayData.Close==null) continue; newData.Open=dayData.Open; newData.High=dayData.High; newData.Low=dayData.Low; newData.YClose=dayData.YClose; newData.Close=dayData.Close; newData.Vol=dayData.Vol; newData.Amount=dayData.Amount; newData.FlowCapital=dayData.FlowCapital; } else { if (newData==null) continue; if (dayData.Open==null || dayData.Close==null) continue; if (newData.Open==null || newData.Close==null) { newData.Open=dayData.Open; newData.High=dayData.High; newData.Low=dayData.Low; newData.YClose=dayData.YClose; newData.Close=dayData.Close; newData.Vol=dayData.Vol; newData.Amount=dayData.Amount; newData.FlowCapital=dayData.FlowCapital; } else { if (newData.HighdayData.Low) newData.Low=dayData.Low; newData.Close=dayData.Close; newData.Vol+=dayData.Vol; if (dayData.Amount!=null) newData.Amount+=dayData.Amount; newData.FlowCapital=dayData.FlowCapital; newData.Date=dayData.Date; } } } return result; } this.GetDayCustomPeriodData=function(count) { var result = []; var periodDataCount = count; var bFirstPeriodData = false; var newData = null; for (var i = 0; i < this.Data.length; ) { bFirstPeriodData = true; for (var j = 0; j < periodDataCount && i < this.Data.length; ++i, ++j) { if (bFirstPeriodData) { newData = new HistoryData(); result.push(newData); bFirstPeriodData = false; } var dayData = this.Data[i]; if (dayData == null) continue; newData.Date = dayData.Date; if (dayData.Open==null || dayData.Close==null) continue; if (newData.Open==null || newData.Close==null) { newData.Open=dayData.Open; newData.High=dayData.High; newData.Low=dayData.Low; newData.YClose=dayData.YClose; newData.Close=dayData.Close; newData.Vol=dayData.Vol; newData.Amount=dayData.Amount; newData.FlowCapital=dayData.FlowCapital; } else { if (newData.HighdayData.Low) newData.Low=dayData.Low; newData.Close=dayData.Close; newData.Vol+=dayData.Vol; if (dayData.Amount!=null) newData.Amount+=dayData.Amount; newData.FlowCapital=dayData.FlowCapital; } } } return result; } //周期数据 1=周 2=月 3=年 this.GetPeriodData=function(period) { if (MARKET_SUFFIX_NAME.IsBIT(this.Symbol)) { if (period==5 || period==6 || period==7 || period==8 || (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END)) //分钟K线 { var periodDataCount = 5; if (period == 5) periodDataCount = 5; else if (period == 6) periodDataCount = 15; else if (period == 7) periodDataCount = 30; else if (period == 8) periodDataCount = 60; else if (period==11) periodDataCount = 120; else if (period==12) periodDataCount = 240; else if (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END) periodDataCount=period-CUSTOM_MINUTE_PERIOD_START; return this.GetMinuteCustomPeriodData(periodDataCount); } } if (period==1 || period==2 || period==3 || period==9 || (period>CUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_END)) return this.GetDayPeriodData(period); if (period==5 || period==6 || period==7 || period==8 || period==11 || period==12 || (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END)) return this.GetMinutePeriodData(period); } //复权 0 不复权 1 前复权 2 后复权 this.GetRightDate=function(right) { var result=[]; if (this.Data.length<=0) return result; if (right==1) { var index=this.Data.length-1; var seed=1; //复权系数 var yClose=this.Data[index].YClose; result[index]=HistoryData.Copy(this.Data[index]); for(--index; index>=0; --index) { if (yClose!=this.Data[index].Close) break; result[index]=HistoryData.Copy(this.Data[index]); yClose=this.Data[index].YClose; } for(; index>=0; --index) { if(yClose!=this.Data[index].Close) seed *= yClose/this.Data[index].Close; result[index]=HistoryData.CopyRight(this.Data[index],seed); yClose=this.Data[index].YClose; } } else if (right==2) { var index=0; var seed=1; var close=this.Data[index].Close; result[index]=HistoryData.Copy(this.Data[index]); for(++index;index=overlayData.length) { result[i]=new HistoryData(); result[i].Date=date; ++i; continue;; } var overlayDate=overlayData[j].Date; if (overlayDate==date) { result[i]=new HistoryData(); result[i].Date=overlayData[j].Date; result[i].YClose=overlayData[j].YClose; result[i].Open=overlayData[j].Open; result[i].High=overlayData[j].High; result[i].Low=overlayData[j].Low; result[i].Close=overlayData[j].Close; result[i].Vol=overlayData[j].Vol; result[i].Amount=overlayData[j].Amount; //涨跌家数数据 result[i].Stop=overlayData[j].Stop; result[i].Up=overlayData[j].Up; result[i].Down=overlayData[j].Down; result[i].Unchanged=overlayData[j].Unchanged; ++j; ++i; } else if (overlayDate=overlayData.length) { result[i]=new HistoryData(); result[i].Date=date; result[i].Time=time; ++i; continue;; } var overlayDate=overlayData[j].Date; var overlayTime=overlayData[j].Time; if (overlayDate==date && overlayTime==time) { result[i]=new HistoryData(); result[i].Date=overlayData[j].Date; result[i].Time=overlayData[j].Time; result[i].YClose=overlayData[j].YClose; result[i].Open=overlayData[j].Open; result[i].High=overlayData[j].High; result[i].Low=overlayData[j].Low; result[i].Close=overlayData[j].Close; result[i].Vol=overlayData[j].Vol; result[i].Amount=overlayData[j].Amount; //涨跌家数数据 result[i].Stop=overlayData[j].Stop; result[i].Up=overlayData[j].Up; result[i].Down=overlayData[j].Down; result[i].Unchanged=overlayData[j].Unchanged; ++j; ++i; } else if (overlayDate=overlayData.length) { result[i]=null; ++i; continue;; } var overlayDate=overlayData[j].Date; if (overlayDate==date) { var item=new SingleData(); item.Date=overlayData[j].Date; item.Value=overlayData[j].Value; result[i]=item; ++j; ++i; } else if (overlayDate=overlayData.length) { result[i]=new SingleData(); result[i].Date=date; result[i].Value=emptyValue; ++i; continue;; } var overlayDate=overlayData[j].Date; if (overlayDate==date) { var item=new SingleData(); item.Date=overlayData[j].Date; item.Value=overlayData[j].Value; result[i]=item; ++j; ++i; } else if (overlayDate=data.length) break; var dateItem=data[j]; if (dateItem.Date==date) { dateItem.Index=i; ++j; } else if (dateItem.Date=data.length) break; var dateTimeItem=data[j]; if (dateTimeItem.Date==date && dateTimeItem.Time==time) { dateTimeItem.Index=i; ++j; } else if (dateTimeItem.Date=overlayData.length) { result[i]=null; ++i; continue;; } var overlayDate=overlayData[j].Date; var overlayTime=overlayData[j].Time; const overlayItem=overlayData[j]; if (overlayDate==date && overlayTime==time) { var item=new SingleData(); item.Date=overlayItem.Date; item.Time=overlayItem.Time; item.Value=overlayItem.Value; result[i]=item; ++j; ++i; } else if (overlayDate=overlayData.length) { result[i]=null; ++i; continue;; } var overlayDate=overlayData[j].Date; if (overlayDate==date) { var item=new SingleData(); item.Date=overlayData[j].Date; item.Value=overlayData[j].Value; item.Text=overlayData[j].Text; result[i]=item; ++j; ++i; } else if (preDate!=null && preDateoverlayDate) { var item=new SingleData(); item.Date=date; item.OverlayDate=overlayData[j].Date; item.Value=overlayData[j].Value; item.Text=overlayData[j].Text; result[i]=item; ++j; ++i; } else if (overlayDate=0;--i) { var date=this.Data[i].Date; var time=this.Data[i].Time; if (firstItem.Date>=date && firstItem.Time>=time) { index=i; break; } } if (index==null) return false; for(var j=index,i=0;i=this.Data.length-1) { if (j-1>0 && !item.YClose) item.YClose=this.Data[j-1].YClose; //前收盘如果没有就是上一记录的收盘 var newItem=HistoryData.Copy(item); this.Data[j]=newItem; ++j; ++i; } else { var oldItem=this.Data[j]; if (oldItem.Date==item.Date && oldItem.Time==item.Time) //更新数据 { HistoryData.CopyTo(oldItem,item); ++j; ++i; } else { ++j; } } } //console.log('[ChartData::MergeMinuteData] ', this.Data, data); return true; } } ChartData.GetFirday=function(value) { var date=new Date(parseInt(value/10000),(value/100%100-1),value%100); var day=date.getDay(); if (day==5) return value; var timestamp=date.getTime(); if (day<5) { var prevTimestamp=(24*60*60*1000)*(5-day); timestamp+=prevTimestamp; } else { var prevTimestamp=(24*60*60*1000)*(day-5); timestamp-=prevTimestamp; } date.setTime(timestamp); var fridayDate= date.getFullYear()*10000+(date.getMonth()+1)*100+date.getDate(); var week=date.getDay(); return fridayDate; } ChartData.GetSunday=function(value) { var date=new Date(parseInt(value/10000),(value/100%100-1),value%100); var day=date.getDay(); if (day==0) return value; var timestamp=date.getTime(); if (day>0) { var prevTimestamp=(24*60*60*1000)*(7-day); timestamp+=prevTimestamp; } date.setTime(timestamp); var sundayDate= date.getFullYear()*10000+(date.getMonth()+1)*100+date.getDate(); var week=date.getDay(); return sundayDate; } ChartData.GetQuarter=function(value) { var month=parseInt(value%10000/100); if (month==1 || month==2 || month==3) return 1; else if (month==4 || month==5 || month==6) return 2; else if (month==7 || month==8 || month==9) return 3; else if (month==10 || month==11 || month==12) return 4; else return 0; } //是否是日线周期 0=日线 1=周线 2=月线 3=年线 9=季线 [40001-50000] 自定义日线 (isIncludeBase 是否包含基础日线周期) var CUSTOM_DAY_PERIOD_START=40000, CUSTOM_DAY_PERIOD_END=50000; ChartData.IsDayPeriod=function(period, isIncludeBase) { if (period==1 || period==2 || period==3 || period==9) return true; if (period>CUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_END) return true; if (period==0 && isIncludeBase==true) return true; return false; } //是否是分钟周期 4=1分钟 5=5分钟 6=15分钟 7=30分钟 8=60分钟 11=120分钟 12=240分钟 [20001-30000] 自定义分钟 (isIncludeBase 是否包含基础1分钟周期) var CUSTOM_MINUTE_PERIOD_START=20000, CUSTOM_MINUTE_PERIOD_END=30000; ChartData.IsMinutePeriod=function(period,isIncludeBase) { if (period==5 || period==6 || period==7 || period==8 ||period==11 || period==12) return true; if (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END) return true; if (period==4 && isIncludeBase==true) return true; return false; } //是否是分笔图 10=分笔 ChartData.IsTickPeriod=function(period) { return period==10; } function TooltipData() //提示信息 { this.ChartPaint; this.Data; this.Type=0; } function Rect(x,y,width,height) { this.X=x, this.Y=y; this.Width=width; this.Height=height; } //图新画法接口类 function IChartPainting() { this.Canvas; //画布 this.ChartBorder; //边框信息 this.ChartFrame; //框架画法 this.Name; //名称 this.ClassName='IChartPainting'; //类名 this.Data=new ChartData(); //数据区 this.NotSupportMessage=null; this.MessageFont=g_JSChartResource.Index.NotSupport.Font; this.MessageColor=g_JSChartResource.Index.NotSupport.TextColor; this.IsDrawFirst=false; this.IsShow=true; this.Draw=function() { } this.DrawNotSupportmessage=function() { this.Canvas.font=this.MessageFont; this.Canvas.fillStyle=this.MessageColor; var left=this.ChartBorder.GetLeft(); var width=this.ChartBorder.GetWidth(); var top=this.ChartBorder.GetTopEx(); var height=this.ChartBorder.GetHeightEx(); var x=left+width/2; var y=top+height/2; this.Canvas.textAlign="center"; this.Canvas.textBaseline="middle"; this.Canvas.fillText(this.NotSupportMessage,x,y); } this.GetTooltipData=function(x,y,tooltip) { return false; } 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;ivalue) range.Min=value; } return range; } this.GetDynamicFont=function(dataWidth) //根据宽度自动获取对应字体 { var pixelTatio = GetDevicePixelRatio(); var font; if (dataWidth < 5) font =4*pixelTatio + 'px Arial'; //字体根据数据宽度动态调整 else if (dataWidth < 7) font = 6*pixelTatio +'px Arial'; else if (dataWidth < 9) font = 8*pixelTatio +'px Arial'; else if (dataWidth < 11) font =10*pixelTatio +'px Arial'; else if (dataWidth < 13) font =12*pixelTatio +'px Arial'; else if (dataWidth < 15) font =14*pixelTatio + 'px Arial'; else font =16*pixelTatio + 'px Arial'; return font; } this.GetLockRect=function() { return this.ChartFrame.GetLockRect(); } } //缩放因子 /* var ZOOM_SEED= [ [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] ]; */ 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], [6,4], [4,4], [3,3], [3,1], [2,1], [1,1], [1,0], ]; //K线画法 支持横屏 function ChartKLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartKLine'; //类名 this.Symbol; //股票代码 this.DrawType=0; // 0=实心K线柱子 1=收盘价线 2=美国线 3=空心K线柱子 4=收盘价面积图 this.CloseLineColor=g_JSChartResource.CloseLineColor; this.CloseLineAreaColor=g_JSChartResource.CloseLineAreaColor; this.UpColor=g_JSChartResource.UpBarColor; this.DownColor=g_JSChartResource.DownBarColor; this.UnchagneColor=g_JSChartResource.UnchagneBarColor; //平盘 this.ColorData; //五彩K线颜色 >0:g_JSChartResource.UpBarColor 其他:g_JSChartResource.DownBarColor this.TradeData; //交易系统 包含买卖数据{Buy:, Sell:} this.TradeIcon=g_JSChartResource.KLine.TradeIcon; this.TooltipRect=new Array(); //2位数组 0 数据序号 1 区域 this.InfoTooltipRect=[]; //2维数组 0 数据, 1 区域 this.IsShowMaxMinPrice=true; //是否显示最大最小值 this.IsShowKTooltip=true; //是否显示K线tooltip this.TextFont=g_JSChartResource.KLine.MaxMin.Font; this.TextColor=g_JSChartResource.KLine.MaxMin.Color; this.InfoData; //信息地雷 key=日期 value=信息数据 this.InfoPosition=0; // 0=K线上 1 底部 this.PtMax; //最大值的位置 this.PtMin; //最小值的位置 this.TickSymbol='╳'; //分笔显示的图标 this.TickFontName='arial'; this.Period; //周期 this.DrawAKLine=function() //美国线 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var upColor=this.UpColor; var downColor=this.DownColor; var unchagneColor=this.UnchagneColor; var ptMax={X:null,Y:null,Value:null,Align:'left'}; var ptMin={X:null,Y:null,Value:null,Align:'left'}; for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yLow=this.ChartFrame.GetYFromData(data.Low); var yHigh=this.ChartFrame.GetYFromData(data.High); var yOpen=this.ChartFrame.GetYFromData(data.Open); var yClose=this.ChartFrame.GetYFromData(data.Close); if (ptMax.Value==null || ptMax.Valuedata.Low) //求最小值 { ptMin.X=x; ptMin.Y=yLow; ptMin.Value=data.Low; ptMin.Align=jdata.Close) this.Canvas.strokeStyle=this.DownColor; //阳线 else this.Canvas.strokeStyle=this.UnchagneColor; //平线 if (this.ColorData) ///五彩K线颜色设置 { if (i0?this.UpColor:this.DownColor); else upColor=downColor=unchagneColor=this.DownColor; } this.Canvas.beginPath(); //最高-最低 if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } this.Canvas.stroke(); if (dataWidth>=4) { this.Canvas.beginPath(); //开盘 if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(yOpen),left); this.Canvas.lineTo(ToFixedPoint(yOpen),x); } else { this.Canvas.moveTo(left,ToFixedPoint(yOpen)); this.Canvas.lineTo(x,ToFixedPoint(yOpen)); } this.Canvas.stroke(); this.Canvas.beginPath(); //收盘 if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(yClose),right); this.Canvas.lineTo(ToFixedPoint(yClose),x); } else { this.Canvas.moveTo(right,ToFixedPoint(yClose)); this.Canvas.lineTo(x,ToFixedPoint(yClose)); } this.Canvas.stroke(); } if(this.Data.DataType==0) { var infoItem={Xleft:left,XRight:right, YMax:yHigh, XCenter:x, YMin:yLow, DayData:data, Index:j}; this.DrawInfo(infoItem); } } this.PtMax=ptMax; this.PtMin=ptMin; } this.DrawCloseArea=function() //收盘价面积图 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var bFirstPoint=true; var firstPoint=null; this.Canvas.beginPath(); this.Canvas.strokeStyle=this.CloseLineColor; for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yClose=this.ChartFrame.GetYFromData(data.Close); if (bFirstPoint) { if (isHScreen) { this.Canvas.moveTo(yClose,x); firstPoint={ X:yClose, Y:x }; } else { this.Canvas.moveTo(x,yClose); firstPoint={ X:x, Y:yClose }; } bFirstPoint=false; } else { if (isHScreen) this.Canvas.lineTo(yClose,x); else this.Canvas.lineTo(x,yClose); } } if (bFirstPoint) return; this.Canvas.stroke(); if (isHScreen) { this.Canvas.lineTo(this.ChartBorder.GetLeft(),x); this.Canvas.lineTo(this.ChartBorder.GetLeft(),firstPoint.Y); } else { this.Canvas.lineTo(x,this.ChartBorder.GetBottom()); this.Canvas.lineTo(firstPoint.X,this.ChartBorder.GetBottom()); } this.Canvas.closePath(); if (Array.isArray(this.CloseLineAreaColor)) { if (isHScreen) { let gradient = this.Canvas.createLinearGradient(this.ChartBorder.GetRightEx(),this.ChartBorder.GetTop(), this.ChartBorder.GetLeft(),this.ChartBorder.GetTop()); gradient.addColorStop(0, this.CloseLineAreaColor[0]); gradient.addColorStop(1, this.CloseLineAreaColor[1]); this.Canvas.fillStyle=gradient; } else { let gradient = this.Canvas.createLinearGradient(firstPoint.X,this.ChartBorder.GetTopEx(), firstPoint.X,this.ChartBorder.GetBottom()); gradient.addColorStop(0, this.CloseLineAreaColor[0]); gradient.addColorStop(1, this.CloseLineAreaColor[1]); this.Canvas.fillStyle=gradient; } } else { this.Canvas.fillStyle=this.CloseLineAreaColor; } this.Canvas.fill(); } this.DrawCloseLine=function() //收盘价线 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var bFirstPoint=true; this.Canvas.beginPath(); this.Canvas.strokeStyle=this.CloseLineColor; for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yClose=this.ChartFrame.GetYFromData(data.Close); if (bFirstPoint) { if (isHScreen) this.Canvas.moveTo(yClose,x); else this.Canvas.moveTo(x,yClose); bFirstPoint=false; } else { if (isHScreen) this.Canvas.lineTo(yClose,x); else this.Canvas.lineTo(x,yClose); } } if (bFirstPoint==false) this.Canvas.stroke(); } this.DrawKBar=function() //蜡烛头 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; if (isHScreen) { xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; chartright=this.ChartBorder.GetBottom(); } var ptMax={X:null,Y:null,Value:null,Align:'left'}; var ptMin={X:null,Y:null,Value:null,Align:'left'}; var upColor=this.UpColor; var downColor=this.DownColor; var unchagneColor=this.UnchagneColor; for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yLow=this.ChartFrame.GetYFromData(data.Low); var yHigh=this.ChartFrame.GetYFromData(data.High); var yOpen=this.ChartFrame.GetYFromData(data.Open); var yClose=this.ChartFrame.GetYFromData(data.Close); var y=yHigh; if (ptMax.Value==null || ptMax.Valuedata.Low) //求最小值 { ptMin.X=x; ptMin.Y=yLow; ptMin.Value=data.Low; ptMin.Align=j0?this.UpColor:this.DownColor); else upColor=downColor=unchagneColor=this.DownColor; } if (data.Open=4) { this.Canvas.strokeStyle=upColor; if (data.High>data.Close) //上影线 { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(this.DrawType==3?Math.max(yClose,yOpen):yClose),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(this.DrawType==3?Math.min(yClose,yOpen):yClose)); } this.Canvas.stroke(); y=yClose; } else { y=yClose; } this.Canvas.fillStyle=upColor; if (isHScreen) { if (Math.abs(yOpen-y)<1) { this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1 } else { if (this.DrawType==3) //空心柱 { this.Canvas.beginPath(); this.Canvas.rect(ToFixedPoint(y),ToFixedPoint(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth)); this.Canvas.stroke(); } else { this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth)); } } } else { if (Math.abs(yOpen-y)<1) { this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1 } else { if (this.DrawType==3) //空心柱 { this.Canvas.beginPath(); this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(y),ToFixedRect(dataWidth),ToFixedRect(yOpen-y)); this.Canvas.stroke(); } else { this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,yOpen)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(yOpen-y))); } } } if (data.Open>data.Low) //下影线 { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(this.DrawType==3?Math.min(yClose,yOpen):y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(this.DrawType==3?Math.max(yClose,yOpen):y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow)); } this.Canvas.stroke(); } } else { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } this.Canvas.strokeStyle=upColor; this.Canvas.stroke(); } } else if (data.Open>data.Close) //阴线 { if (dataWidth>=4) { this.Canvas.strokeStyle=downColor; if (data.High>data.Close) //上影线 { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yOpen),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yOpen)); } this.Canvas.stroke(); y=yOpen; } else { y=yOpen } this.Canvas.fillStyle=downColor; if (isHScreen) { if (Math.abs(yClose-y)<1) this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1 else this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yClose-y),ToFixedRect(dataWidth)); } else { if (Math.abs(yClose-y)<1) this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1 else this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,yClose)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(yClose-y))); } if (data.Open>data.Low) //下影线 { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow)); } this.Canvas.stroke(); } } else { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } this.Canvas.strokeStyle=downColor; this.Canvas.stroke(); } } else // 平线 { if (dataWidth>=4) { this.Canvas.strokeStyle=unchagneColor; this.Canvas.beginPath(); if (data.High>data.Close) //上影线 { if (isHScreen) { this.Canvas.moveTo(y,ToFixedPoint(x)); this.Canvas.lineTo(yOpen,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),y); this.Canvas.lineTo(ToFixedPoint(x),yOpen); } y=yOpen; } else { y=yOpen; } if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(left)); this.Canvas.lineTo(ToFixedPoint(y),ToFixedPoint(right)); } else { this.Canvas.moveTo(ToFixedPoint(left),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(y)); } if (data.Open>data.Low) //下影线 { if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow)); } } this.Canvas.stroke(); } else { this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } this.Canvas.strokeStyle=unchagneColor; this.Canvas.stroke(); } } if (this.IsShowKTooltip && !isHScreen) //添加tooltip区域 { var yTop=Math.min(yOpen,yClose); var yBottom=Math.max(yOpen,yClose); if (Math.abs(yOpen-yClose)<5) //高度太小了, 上下各+5px { yTop=Math.min(yHigh,yTop-5); yBottom=Math.max(yLow,yBottom+5); } var rect=new Rect(left,yTop,dataWidth,yBottom-yTop); //this.Canvas.fillStyle="rgb(0,0,100)"; //this.Canvas.fillRect(rect.X,rect.Y,rect.Width,rect.Height); this.TooltipRect.push([i,rect]); //[0]数据索引 [1]数据区域 } if(this.Data.DataType==0) { var infoItem={Xleft:left,XRight:right, XCenter:x, YMax:yHigh, YMin:yLow, DayData:data, Index:j}; this.DrawInfo(infoItem); } } this.PtMax=ptMax; this.PtMin=ptMin; } this.DrawTrade=function() //交易系统 { if (!this.TradeData) return; var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; if (isHScreen) { xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; chartright=this.ChartBorder.GetBottom(); } var sellData=this.TradeData.Sell; var buyData=this.TradeData.Buy; var arrowWidth=dataWidth; if (arrowWidth>10) arrowWidth=10; for(var i=this.Data.DataOffset,j=0;i0; if (buyData && i0; if (!sell && !buy) continue; var left=xOffset; var right=xOffset+dataWidth; if (right>chartright) break; var x=left+(right-left)/2; var yLow=this.ChartFrame.GetYFromData(data.Low); var yHigh=this.ChartFrame.GetYFromData(data.High); var yOpen=this.ChartFrame.GetYFromData(data.Open); var yClose=this.ChartFrame.GetYFromData(data.Close); var y=yHigh; if (buy) { this.Canvas.fillStyle=this.UpColor; this.Canvas.strokeStyle=this.UnchagneColor; this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(yLow-1,x); this.Canvas.lineTo(yLow-arrowWidth-1,x-arrowWidth/2); this.Canvas.lineTo(yLow-arrowWidth-1,x+arrowWidth/2); } else { this.Canvas.moveTo(x,yLow+1); this.Canvas.lineTo(x-arrowWidth/2,yLow+arrowWidth+1); this.Canvas.lineTo(x+arrowWidth/2,yLow+arrowWidth+1); } this.Canvas.closePath(); this.Canvas.fill(); this.Canvas.stroke(); } if (sell) { this.Canvas.fillStyle=this.DownColor; this.Canvas.strokeStyle=this.UnchagneColor; this.Canvas.beginPath(); if (isHScreen) { this.Canvas.moveTo(yHigh+1,x); this.Canvas.lineTo(yHigh+arrowWidth+1,x-arrowWidth/2); this.Canvas.lineTo(yHigh+arrowWidth+1,x+arrowWidth/2); } else { this.Canvas.moveTo(x,yHigh-1); this.Canvas.lineTo(x-arrowWidth/2,yHigh-arrowWidth-1); this.Canvas.lineTo(x+arrowWidth/2,yHigh-arrowWidth-1); } this.Canvas.closePath(); this.Canvas.fill(); this.Canvas.stroke(); } } } this.DrawTick=function() //分笔图 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var fontSize=parseInt(dataWidth); if (fontSize<=1) fontSize=2; else if (fontSize>=18) fontSize=18; var bFirstPoint=true; this.Canvas.beginPath(); this.Canvas.font=fontSize*GetDevicePixelRatio()+'px '+this.TickFontName; for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yClose=this.ChartFrame.GetYFromData(data.Close); if (data.Flag===0) this.Canvas.fillStyle=this.UpColor; else if (data.Flag==1) this.Canvas.fillStyle=this.DownColor; else this.Canvas.fillStyle=this.UnchagneColor; this.Canvas.textAlign='center' this.Canvas.textBaseline='middle'; if (isHScreen) this.Canvas.fillText(this.TickSymbol,yClose,x); else this.Canvas.fillText(this.TickSymbol,x,yClose); } } this.Draw=function() { this.TooltipRect=[]; this.InfoTooltipRect=[]; this.PtMax={X:null,Y:null,Value:null,Align:'left'}; //清空最大 this.PtMin={X:null,Y:null,Value:null,Align:'left'}; //清空最小 this.ChartFrame.ChartKLine={Max:null, Min:null }; //保存K线上 显示最大最小值坐标 if (!this.IsShow) return; if (ChartData.IsTickPeriod(this.Period)) //分笔图 { this.DrawTick(); return; } if (this.DrawType==1) { this.DrawCloseLine(); return; } else if (this.DrawType==2) { this.DrawAKLine(); } else if (this.DrawType==4) { this.DrawCloseArea(); } else { this.DrawKBar(); } if (this.TradeIcon) this.DrawTradeIcon() else this.DrawTrade(); if (this.IsShowMaxMinPrice) //标注最大值最小值 { if (this.ChartFrame.IsHScreen===true) this.HScreenDrawMaxMinPrice(this.PtMax,this.PtMin); else this.DrawMaxMinPrice(this.PtMax,this.PtMin); } } this.DrawMaxMinPrice=function(ptMax,ptMin) { if (ptMax.X==null || ptMax.Y==null || ptMax.Value==null) return; if (ptMin.X==null || ptMin.Y==null || ptMin.Value==null) return; var defaultfloatPrecision=GetfloatPrecision(this.Symbol); this.Canvas.font=this.TextFont; this.Canvas.fillStyle=this.TextColor; var ptTop=ptMax; if (ptMax.Y>ptMin.Y) ptTop=ptMin; this.Canvas.textAlign=ptTop.Align; this.Canvas.textBaseline='bottom'; var left=ptTop.Align=='left'?ptTop.X:ptTop.X; var text=ptTop.Value.toFixed(defaultfloatPrecision); if (ptTop.Align=='left') text='←'+text; else text=text+'→'; this.Canvas.fillText(text,left,ptTop.Y); this.ChartFrame.ChartKLine.Max={X:left, Y:ptTop.Y, Text: { BaseLine:'bottom'}}; var ptBottom=ptMin; if (ptMin.Y=2 && numText && bShowNum) //太小了 就不显示了 { var iconID=value.Data.length; if (iconID>=numText.length) iconID=0; this.Canvas.fillStyle=g_JSChartResource.KLine.NumIcon.Color; var text=numText[iconID]; this.Canvas.fillText(text,value.TextRect.X,value.TextRect.Y,iconSize); } if (!isHScreen) this.InfoTooltipRect.push(value); //横屏没有tooltip } } //画交易图标 this.DrawTradeIcon=function() { if (!this.TradeData) return; var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; if (isHScreen) { xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; chartright=this.ChartBorder.GetBottom(); } var sellData=this.TradeData.Sell; var buyData=this.TradeData.Buy; var iconSize=dataWidth+distanceWidth; var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 var iconSizeMax=24*pixelTatio,iconSizeMin=12*pixelTatio; if (iconSizeiconSizeMax) iconSize=iconSizeMax; this.Canvas.font=iconSize+'px '+this.TradeIcon.Family; for(var i=this.Data.DataOffset,j=0;i0; if (buyData && i0; if (!sell && !buy) continue; var left=xOffset; var right=xOffset+dataWidth; if (right>chartright) break; var x=left+(right-left)/2; var yLow=this.ChartFrame.GetYFromData(data.Low); var yHigh=this.ChartFrame.GetYFromData(data.High); var yOpen=this.ChartFrame.GetYFromData(data.Open); var yClose=this.ChartFrame.GetYFromData(data.Close); var y=yHigh; if (buy) { this.Canvas.fillStyle=this.TradeIcon.Buy.Color; if (isHScreen) { this.Canvas.textAlign='right'; this.Canvas.textBaseline='middle'; this.Canvas.fillText(this.TradeIcon.Buy.HScreenText,yLow,x); } else { this.Canvas.textAlign='center'; this.Canvas.textBaseline='top'; this.Canvas.fillText(this.TradeIcon.Buy.Text,x,yLow); } } if (sell) { this.Canvas.fillStyle=this.TradeIcon.Sell.Color; if (isHScreen) { this.Canvas.textAlign='left'; this.Canvas.textBaseline='middle'; this.Canvas.fillText(this.TradeIcon.Sell.HScreenText,yHigh,x); } else { this.Canvas.textAlign='center'; this.Canvas.textBaseline='bottom'; this.Canvas.fillText(this.TradeIcon.Sell.Text,x,yHigh); } } } } this.GetTooltipData=function(x,y,tooltip) { for(var i in this.InfoTooltipRect) { var item=this.InfoTooltipRect[i]; if (!item.Rect) continue; var rect=item.Rect; this.Canvas.beginPath(); this.Canvas.rect(rect.X,rect.Y,rect.Width,rect.Height); if (this.Canvas.isPointInPath(x,y)) { //console.log('[ChartKLine::GetTooltipData]', item); tooltip.Data=item; tooltip.ChartPaint=this; tooltip.Type=1; //信息地雷 return true; } } for(var i in this.TooltipRect) { var rect=this.TooltipRect[i][1]; this.Canvas.beginPath(); this.Canvas.rect(rect.X,rect.Y,rect.Width,rect.Height); if (this.Canvas.isPointInPath(x,y)) { var index=this.TooltipRect[i][0]; tooltip.Data=this.Data.Data[index]; tooltip.ChartPaint=this; tooltip.Type=0; //K线信息 return true; } } return false; } //计算当天显示数据的最大最小值 this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Max=null; range.Min=null; for(var i=this.Data.DataOffset,j=0;idata.Low) range.Min=data.Low; } return range; } //获取所有的价格 this.GetAllPrice=function() { var xPointCount=this.ChartFrame.XPointCount; var setPrice=new Set(); for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yLow=this.ChartFrame.GetYFromData(data.Low/firstOverlayOpen*firstOpen); var yHigh=this.ChartFrame.GetYFromData(data.High/firstOverlayOpen*firstOpen); var yOpen=this.ChartFrame.GetYFromData(data.Open/firstOverlayOpen*firstOpen); var yClose=this.ChartFrame.GetYFromData(data.Close/firstOverlayOpen*firstOpen); var y=yHigh; if (data.Open=4) { if (data.High>data.Close) //上影线 { if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(this.DrawType==3?Math.max(yClose,yOpen):yClose),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(this.DrawType==3?Math.min(yClose,yOpen):yClose)); } y=yClose; } else { y=yClose; } if (isHScreen) { if (Math.abs(yOpen-y)<1) { this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1 } else { if (drawType==3) this.Canvas.rect(ToFixedPoint(y),ToFixedPoint(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth)); //空心柱 else this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yOpen-y),ToFixedRect(dataWidth)); } } else { if (Math.abs(yOpen-y)<1) { this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1 } else { if (drawType==3) this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(y),ToFixedRect(dataWidth),ToFixedRect(yOpen-y)); //空心柱 else this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),ToFixedRect(yOpen-y)); } } if (data.Open>data.Low) { if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(this.DrawType==3?Math.min(yClose,yOpen):y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(this.DrawType==3?Math.max(yClose,yOpen):y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow)); } } } else { if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } } } else if (data.Open>data.Close) //阴线 { if (dataWidth>=4) { if (data.High>data.Close) //上影线 { if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yOpen),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yOpen)); } y=yOpen; } else { y=yOpen } if (isHScreen) { if (Math.abs(yClose-y)<1) this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),1,ToFixedRect(dataWidth)); //高度小于1,统一使用高度1 else this.Canvas.fillRect(ToFixedRect(y),ToFixedRect(left),ToFixedRect(yClose-y),ToFixedRect(dataWidth)); } else { if (Math.abs(yClose-y)<1) this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),1); //高度小于1,统一使用高度1 else this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(y),ToFixedRect(dataWidth),ToFixedRect(yClose-y)); } if (data.Open>data.Low) //下影线 { if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow)); } } } else { if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } } } else // 平线 { if (dataWidth>=4) { if (data.High>data.Close) //上影线 { if (isHScreen) { this.Canvas.moveTo(y,ToFixedPoint(x)); this.Canvas.lineTo(yOpen,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),y); this.Canvas.lineTo(ToFixedPoint(x),yOpen); } y=yOpen; } else { y=yOpen; } if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(left)); this.Canvas.lineTo(ToFixedPoint(y),ToFixedPoint(right)); } else { this.Canvas.moveTo(ToFixedPoint(left),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(right),ToFixedPoint(y)); } if (data.Open>data.Low) //下影线 { if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(y),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(yLow),ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(y)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(yLow)); } } } else { if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } } } //添加tooltip区域 { var yTop=Math.min(yLow,yHigh,yOpen,yClose); var yBottom=Math.max(yLow,yHigh,yOpen,yClose); var rect=new Rect(left,yTop,dataWidth,yBottom-yTop); //this.Canvas.fillStyle="rgb(0,0,100)"; //this.Canvas.fillRect(rect.X,rect.Y,rect.Width,rect.Height); this.TooltipRect.push([i,rect]); //[0]数据索引 [1]数据区域 } } if (isFristDraw==false) this.Canvas.stroke(); } this.DrawAKLine=function(firstOpen) //美国线 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var firstOverlayOpen=null; this.Canvas.strokeStyle=this.Color; for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yLow=this.ChartFrame.GetYFromData(data.Low/firstOverlayOpen*firstOpen); var yHigh=this.ChartFrame.GetYFromData(data.High/firstOverlayOpen*firstOpen); var yOpen=this.ChartFrame.GetYFromData(data.Open/firstOverlayOpen*firstOpen); var yClose=this.ChartFrame.GetYFromData(data.Close/firstOverlayOpen*firstOpen); this.Canvas.beginPath(); //最高-最低 if (isHScreen) { this.Canvas.moveTo(yHigh,ToFixedPoint(x)); this.Canvas.lineTo(yLow,ToFixedPoint(x)); } else { this.Canvas.moveTo(ToFixedPoint(x),yHigh); this.Canvas.lineTo(ToFixedPoint(x),yLow); } this.Canvas.stroke(); if (dataWidth>=4) { this.Canvas.beginPath(); //开盘 if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(yOpen),left); this.Canvas.lineTo(ToFixedPoint(yOpen),x); } else { this.Canvas.moveTo(left,ToFixedPoint(yOpen)); this.Canvas.lineTo(x,ToFixedPoint(yOpen)); } this.Canvas.stroke(); this.Canvas.beginPath(); //收盘 if (isHScreen) { this.Canvas.moveTo(ToFixedPoint(yClose),right); this.Canvas.lineTo(ToFixedPoint(yClose),x); } else { this.Canvas.moveTo(right,ToFixedPoint(yClose)); this.Canvas.lineTo(x,ToFixedPoint(yClose)); } this.Canvas.stroke(); } } } this.DrawCloseLine=function(firstOpen) //收盘价线 { var isHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var firstOverlayOpen=null; var bFirstPoint=true; this.Canvas.strokeStyle=this.Color; this.Canvas.beginPath(); for(var i=this.Data.DataOffset,j=0;ichartright) break; var x=left+(right-left)/2; var yClose=this.ChartFrame.GetYFromData(data.Close/firstOverlayOpen*firstOpen); if (bFirstPoint) { if (isHScreen) this.Canvas.moveTo(yClose,x); else this.Canvas.moveTo(x,yClose); bFirstPoint=false; } else { if (isHScreen) this.Canvas.lineTo(yClose,x); else this.Canvas.lineTo(x,yClose); } } if (bFirstPoint==false) this.Canvas.stroke(); } this.Draw=function() { this.TooltipRect=[]; this.InfoTooltipRect=[]; if (!this.MainData || !this.Data) return; var xPointCount=this.ChartFrame.XPointCount; var firstOpen=null; //主线数据第1个开盘价 for(var i=this.Data.DataOffset,j=0;ilow) range.Min=low; } return range; } this.GetTooltipData=function(x,y,tooltip) { for(var i in this.TooltipRect) { var rect=this.TooltipRect[i][1]; this.Canvas.beginPath(); this.Canvas.rect(rect.X,rect.Y,rect.Width,rect.Height); if (this.Canvas.isPointInPath(x,y)) { var index=this.TooltipRect[i][0]; tooltip.Data=this.Data.Data[index]; tooltip.ChartPaint=this; return true; } } return false; } } //分钟成交量 支持横屏 function ChartMinuteVolumBar() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartMinuteVolumBar'; //类名 this.UpColor = g_JSChartResource.UpBarColor; this.DownColor = g_JSChartResource.DownBarColor; this.YClose; //前收盘 this.Draw=function() { var isHScreen = (this.ChartFrame.IsHScreen === true); var chartright=this.ChartBorder.GetRight(); if (isHScreen) chartright = this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var yBottom=this.ChartFrame.GetYFromData(0); var yPrice=this.YClose; //上一分钟的价格 var data=this.Data; for(var i=data.DataOffset,j=0;ichartright) break; //价格>=上一分钟价格 红色 否则绿色 this.Canvas.strokeStyle = price >= yPrice ? this.UpColor:this.DownColor; 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(); if (price) yPrice=price; } } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=0; range.Max=null; for(var i=this.Data.DataOffset,j=0;i0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio(); var bFirstPoint=true; var drawCount=0; for(var i=this.Data.DataOffset,j=0;ichartright) break; if (bFirstPoint) { this.Canvas.strokeStyle=this.Color; this.Canvas.beginPath(); if (bHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调 else this.Canvas.moveTo(x,y); bFirstPoint=false; } else { if (bHScreen) this.Canvas.lineTo(y,x); else this.Canvas.lineTo(x,y); } ++drawCount; } if (drawCount>0) this.Canvas.stroke(); this.Canvas.restore(); } //无效数不画 this.DrawStraightLine=function() { var bHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); if (bHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var lockRect=this.GetLockRect(); if (lockRect) { if (bHScreen) chartright=lockRect.Top; else chartright=lockRect.Left; } this.Canvas.save(); if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio(); this.Canvas.strokeStyle=this.Color; if (this.IsDotLine) this.Canvas.setLineDash([3,5]); //画虚线 var bFirstPoint=true; var drawCount=0; for(var i=this.Data.DataOffset,j=0;i0) this.Canvas.stroke(); bFirstPoint=true; drawCount=0; continue; } var x=this.ChartFrame.GetXFromIndex(j); var y=this.ChartFrame.GetYFromData(value); if (x>chartright) break; if (bFirstPoint) { this.Canvas.beginPath(); if (bHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调 else this.Canvas.moveTo(x,y); bFirstPoint=false; } else { if (bHScreen) this.Canvas.lineTo(y,x); else this.Canvas.lineTo(x,y); } ++drawCount; } if (drawCount>0) this.Canvas.stroke(); this.Canvas.restore(); } } //彩色线段 function ChartPartLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartPartLine'; //类名 this.LineWidth; //线段宽度 this.Draw=function() { if (!this.IsShow) return; if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.Data || !this.Data.Data) return; this.DrawLine(); } this.DrawLine=function() { var bHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); if (bHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; this.Canvas.save(); if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio(); var bFirstPoint=true; var drawCount=0; var lastColor; var lastPoint={X:null,Y:null}; for(var i=this.Data.DataOffset,j=0;ichartright) break; if (color!=lastColor) { if (lastColor && drawCount>0) this.Canvas.stroke(); drawCount=0; lastColor=color; this.Canvas.strokeStyle=color; this.Canvas.beginPath(); if (lastPoint.X!=null && lastPoint.Y!=null) //接着上一个点连线 { if (bHScreen) this.Canvas.moveTo(lastPoint.Y,lastPoint.X); //横屏坐标轴对调 else this.Canvas.moveTo(lastPoint.X,lastPoint.Y); if (bHScreen) this.Canvas.lineTo(y,x); else this.Canvas.lineTo(x,y); ++drawCount; } else { if (bHScreen) this.Canvas.moveTo(y,x); //横屏坐标轴对调 else this.Canvas.moveTo(x,y); } } else { if (bHScreen) this.Canvas.lineTo(y,x); else this.Canvas.lineTo(x,y); ++drawCount; } lastPoint.X=x; lastPoint.Y=y; } if (drawCount>0) this.Canvas.stroke(); this.Canvas.restore(); } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=null; range.Max=null; for(var i=this.Data.DataOffset,j=0;iitem.Value) range.Min = item.Value; } return range; } } //POINTDOT 圆点 支持横屏 function ChartPointDot() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartPointDot'; //类名 this.Color="rgb(255,193,37)"; //线段颜色 this.Radius=1; //点半径 this.Draw=function() { if (!this.IsShow) return; if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.Data || !this.Data.Data) return; var bHScreen=(this.ChartFrame.IsHScreen===true); var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); if (bHScreen===true) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; this.Canvas.save(); this.Canvas.fillStyle=this.Color; for(var i=this.Data.DataOffset,j=0;ichartright) break; this.Canvas.beginPath(); if (bHScreen) this.Canvas.arc(y, x, this.Radius, 0, Math.PI*2, true); else this.Canvas.arc(x, y, this.Radius, 0, Math.PI*2, true); this.Canvas.closePath(); this.Canvas.fill(); } this.Canvas.restore(); } } //通达信语法 STICK 支持横屏 function ChartStick() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Color="rgb(255,193,37)"; //线段颜色 this.LineWidth; //线段宽度 this.ClassName='ChartStick'; this.DrawLine=function() { 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===true) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; this.Canvas.save(); if (this.LineWidth>0) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio(); var bFirstPoint=true; var drawCount=0; for(var i=this.Data.DataOffset,j=0;ichartright) break; 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.Canvas.restore(); } this.DrawStick=function() { if (!this.Data || !this.Data.Data) return; var bHScreen=(this.ChartFrame.IsHScreen===true); var chartright=this.ChartBorder.GetRight(); if (bHScreen) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var yBottom=this.ChartBorder.GetBottom(); var xLeft=this.ChartBorder.GetLeft(); this.Canvas.save(); this.Canvas.strokeStyle=this.Color; if (this.LineWidth) this.Canvas.lineWidth=this.LineWidth * GetDevicePixelRatio(); for(var i=this.Data.DataOffset,j=0;ichartright) break; this.Canvas.beginPath(); if (bHScreen) { this.Canvas.moveTo(xLeft,x); this.Canvas.lineTo(y,x); this.Canvas.stroke(); } else { var xFix=parseInt(x.toString())+0.5; this.Canvas.moveTo(xFix,y); this.Canvas.lineTo(xFix,yBottom); } this.Canvas.stroke(); } this.Canvas.restore(); } this.Draw=function() { if (!this.IsShow) return; if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.Data || !this.Data.Data) return; this.DrawStick(); } } //通达信语法 LINESTICK 支持横屏 function ChartLineStick() { this.newMethod=ChartStick; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartLineStick'; this.Draw=function() { if (!this.IsShow) return; if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } this.DrawStick(); this.DrawLine(); } } //通达信语法 VOLSTICK 支持横屏 function ChartVolStick() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.UpColor=g_JSChartResource.UpBarColor; this.DownColor=g_JSChartResource.DownBarColor; this.HistoryData; //历史数据 this.KLineDrawType=0; this.ClassName='ChartVolStick'; this.Draw=function() { if (this.ChartFrame.IsHScreen===true) { this.HScreenDraw(); return; } var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; var lockRect=this.GetLockRect(); if (lockRect) chartright=lockRect.Left; var yBottom=this.ChartFrame.GetYFromData(0); if (dataWidth>=4) { yBottom=ToFixedRect(yBottom); for(var i=this.Data.DataOffset,j=0;ichartright) break; var y=this.ChartFrame.GetYFromData(value); var bUp=false; if (kItem.Close>=kItem.Open) { this.Canvas.fillStyle=this.UpColor; bUp=true; } else { this.Canvas.fillStyle=this.DownColor; } var height=ToFixedRect(yBottom-y);//高度调整为整数 y=yBottom-height; if (bUp && (this.KLineDrawType==1 || this.KLineDrawType==2 || this.KLineDrawType==3)) //空心柱子 { this.Canvas.strokeStyle=this.UpColor; this.Canvas.beginPath(); this.Canvas.rect(ToFixedPoint(left),ToFixedPoint(y),ToFixedRect(dataWidth),height); this.Canvas.stroke(); } else { this.Canvas.fillRect(ToFixedRect(left),y,ToFixedRect(dataWidth),height); } } } else //太细了直接话线 { for(var i=this.Data.DataOffset,j=0;ichartright) break; if (kItem.Close>=kItem.Open) this.Canvas.strokeStyle=this.UpColor; else this.Canvas.strokeStyle=this.DownColor; var x=this.ChartFrame.GetXFromIndex(j); this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(x),y); this.Canvas.lineTo(ToFixedPoint(x),yBottom); this.Canvas.stroke(); } } } this.HScreenDraw=function() //横屏画法 { var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; var chartBottom=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var lockRect=this.GetLockRect(); if (lockRect) chartBottom=lockRect.Top; var yBottom=this.ChartFrame.GetYFromData(0); if (dataWidth>=4) { yBottom=ToFixedRect(yBottom); for(var i=this.Data.DataOffset,j=0;ichartBottom) break; var y=this.ChartFrame.GetYFromData(value); var bUp=false; if (kItem.Close>=kItem.Open) { bUp=true; this.Canvas.fillStyle=this.UpColor; } else { this.Canvas.fillStyle=this.DownColor; } var height=ToFixedRect(y-yBottom); //高度调整为整数 if (bUp && (this.KLineDrawType==1 || this.KLineDrawType==2 || this.KLineDrawType==3)) //空心柱子 { this.Canvas.strokeStyle=this.UpColor; this.Canvas.beginPath(); this.Canvas.rect(ToFixedPoint(yBottom),ToFixedPoint(left),height,ToFixedRect(dataWidth)); this.Canvas.stroke(); } else { this.Canvas.fillRect(yBottom,ToFixedRect(left),height,ToFixedRect(dataWidth)); } } } else //太细了直接话线 { for(var i=this.Data.DataOffset,j=0;ichartBottom) break; if (kItem.Close>kItem.Open) this.Canvas.strokeStyle=this.UpColor; else this.Canvas.strokeStyle=this.DownColor; var x=this.ChartFrame.GetXFromIndex(j); this.Canvas.beginPath(); this.Canvas.moveTo(y,ToFixedPoint(x)); this.Canvas.lineTo(yBottom,ToFixedPoint(x)); 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;ichartright) 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;ivalue) range.Min=value; } } return range; } } //柱子 支持横屏 function ChartStickLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartStickLine'; //类名 this.Color="rgb(255,193,37)"; //线段颜色 this.LineWidth=2*GetDevicePixelRatio(); //线段宽度 this.BarType=0; //柱子类型 0=实心 1=空心 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 xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; if (isHScreen) xOffset=this.ChartBorder.GetTop()+distanceWidth/2.0+2.0; this.Canvas.save(); var bFillBar=false; var bFillKLine=false; if (this.LineWidth==50) //宽度==50 跟K线宽度保持一致 { if (dataWidth>=4) { bFillKLine=true; this.Canvas.fillStyle=this.Color; this.Canvas.strokeStyle=this.Color; } else //太细了 画竖线 { this.Canvas.lineWidth=GetDevicePixelRatio(); this.Canvas.strokeStyle=this.Color; } } else if (this.LineWidth<100) { var LineWidth=this.LineWidth; if (dataWidth<=4) LineWidth=GetDevicePixelRatio(); else if (dataWidthchartright) break; if (bFillBar) { if (isHScreen) { var left=xOffset-fixedWidth; this.Canvas.fillRect(Math.min(y,y2),left,Math.abs(y-y2),dataWidth+distanceWidth+fixedWidth*2); } else { var left=xOffset-fixedWidth; var barWidth=dataWidth+distanceWidth+fixedWidth*2; if (left+barWidth>chartright) barWidth=chartright-left; //不要超过右边框子 this.Canvas.fillRect(ToFixedRect(left),ToFixedRect(Math.min(y,y2)),ToFixedRect(barWidth),ToFixedRect(Math.abs(y-y2))); } } else if (bFillKLine) { if (this.BarType==1) //实心 { if (isHScreen) { this.Canvas.beginPath(); this.Canvas.fillRect(ToFixedRect(Math.min(y,y2)),ToFixedRect(xOffset),ToFixedRect(Math.abs(y-y2)),ToFixedRect(dataWidth)); this.Canvas.stroke(); } else { this.Canvas.beginPath(); this.Canvas.rect(ToFixedRect(xOffset),ToFixedRect(Math.min(y,y2)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(y-y2))); this.Canvas.stroke(); } } else { if (isHScreen) this.Canvas.fillRect(ToFixedRect(Math.min(y,y2)),ToFixedRect(xOffset),ToFixedRect(Math.abs(y-y2)),ToFixedRect(dataWidth)); else this.Canvas.fillRect(ToFixedRect(xOffset),ToFixedRect(Math.min(y,y2)),ToFixedRect(dataWidth),ToFixedRect(Math.abs(y-y2))); } } else { if (isHScreen) { this.Canvas.beginPath(); this.Canvas.moveTo(y,ToFixedPoint(x)); this.Canvas.lineTo(y2,ToFixedPoint(x)); this.Canvas.stroke(); } else { var xFix=parseInt(x.toString())+0.5; this.Canvas.beginPath(); this.Canvas.moveTo(xFix,y); this.Canvas.lineTo(xFix,y2); this.Canvas.stroke(); } } } this.Canvas.restore(); } 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;ivalueMin) range.Min=valueMin; } return range; } } function ChartText() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartText'; //类名 this.TextFont="14px 微软雅黑"; this.Draw=function() { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.Data || !this.Data.Data) return; var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; for(var i in this.Data.Data) { var value=this.Data.Data[i]; if (value==null) continue; var price=value.Value; var position=value.Position; if (position=='Left') { var x=this.ChartFrame.GetXFromIndex(0); var y=this.ChartFrame.GetYFromData(price); if (x>chartright) continue; this.Canvas.textAlign='left'; this.Canvas.textBaseline='middle'; this.Canvas.fillStyle=value.Color; this.Canvas.font=this.TextFont; this.Canvas.fillText(value.Message,x,y); } } } 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 in this.Data.Data) { var data=this.Data.Data[i]; if (data==null || isNaN(data.Value)) continue; var value=data.Value; if (range.Max==null) range.Max=value; if (range.Min==null) range.Min=value; if (range.Maxvalue) range.Min=value; } return range; } } /* 文字输出 支持横屏 数组不为null的数据中输出 this.Text文本 */ function ChartSingleText() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartSingleText'; //类名 this.Color="rgb(255,193,37)"; //线段颜色 this.TextFont="14px 微软雅黑"; //线段宽度 this.Text; this.TextAlign='left'; this.Direction=0; //0=middle 1=bottom 2=top this.YOffset=0; this.Position; //指定输出位置 this.IconFont; //Iconfont this.Draw=function() { if (!this.IsShow) return; if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (this.Position) { this.DrawPosition(); 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(); var top=this.ChartBorder.GetTopEx(); var bottom=this.ChartBorder.GetBottomEx(); if (isHScreen) { chartright=this.ChartBorder.GetBottom(); top=this.ChartBorder.GetRightEx(); bottom=this.ChartBorder.GetLeftEx(); } var xPointCount=this.ChartFrame.XPointCount; var isArrayText=Array.isArray(this.Text); var pixelTatio = GetDevicePixelRatio(); if (this.Direction==1) this.Canvas.textBaseline='bottom'; else if (this.Direction==2) this.Canvas.textBaseline='top'; else this.Canvas.textBaseline='middle'; if (this.IconFont) { this.Color=this.IconFont.Color; this.Text=this.IconFont.Text; var iconSize=dataWidth; var minIconSize=12*pixelTatio; var maxIconSize=24*pixelTatio; if (iconSizemaxIconSize) iconSize=maxIconSize; this.Canvas.font=iconSize+'px '+this.IconFont.Family; } else { this.TextFont=this.GetDynamicFont(dataWidth*2*pixelTatio); this.Canvas.font=this.TextFont; } for(var i=this.Data.DataOffset,j=0;ichartright) break; this.Canvas.textAlign=this.TextAlign; this.Canvas.fillStyle=this.Color; if (this.YOffset>0 && this.Direction>0) { var yPrice=y; this.Canvas.save(); this.Canvas.setLineDash([5,10]); this.Canvas.strokeStyle=this.Color; this.Canvas.beginPath(); if (isHScreen) { if (this.Direction==1) { y=top-this.YOffset*pixelTatio; yPrice+=5*pixelTatio; } else { y=bottom+this.YOffset*pixelTatio; yPrice-=5*pixelTatio; } this.Canvas.moveTo(ToFixedPoint(yPrice),ToFixedPoint(x)); this.Canvas.lineTo(ToFixedPoint(y),ToFixedPoint(x)); } else { if (this.Direction==1) { y=top+this.YOffset*pixelTatio; yPrice+=5*pixelTatio; } else { y=bottom-this.YOffset*pixelTatio; yPrice-=5*pixelTatio; } this.Canvas.moveTo(ToFixedPoint(x),ToFixedPoint(yPrice)); this.Canvas.lineTo(ToFixedPoint(x),ToFixedPoint(y)); } this.Canvas.stroke(); this.Canvas.restore(); } if (isArrayText) { var text=this.Text[i]; if (!text) continue; this.DrawText(text,x,y,isHScreen); } else { //console.log('[ChartSingleText::Draw] ',this.Direction,this.Text) this.DrawText(this.Text,x,y,isHScreen); } } } this.DrawPosition=function() //绘制在指定位置上 { if (!this.Text) return; var isHScreen=(this.ChartFrame.IsHScreen===true) if (isHScreen) { var x=this.ChartBorder.GetLeft()+this.ChartBorder.GetWidthEx()*this.Position.Y; var y=this.ChartBorder.GetTop()+this.ChartBorder.GetHeight()*this.Position.X; } else { var x=this.ChartBorder.GetLeft()+this.ChartBorder.GetWidth()*this.Position.X; var y=this.ChartBorder.GetTopEx()+this.ChartBorder.GetHeight()*this.Position.Y; } if (isHScreen) { chartright=this.ChartBorder.GetBottom(); top=this.ChartBorder.GetRightEx(); bottom=this.ChartBorder.GetLeftEx(); } this.Canvas.fillStyle=this.Color; if (this.Position.Type==0) this.Canvas.textAlign='left'; else if (this.Position.Type==2) this.Canvas.textAlign='center'; else this.Canvas.textAlign='right'; this.DrawText(this.Text,x,y,isHScreen); } this.DrawText=function(text,x,y,isHScreen) { if (isHScreen) { this.Canvas.save(); this.Canvas.translate(y, x); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.fillText(text,0,0); this.Canvas.restore(); } else { this.Canvas.fillText(text,x,y); /* var textWidth=this.Canvas.measureText(text).width; var rectSize=textWidth*2; var xRect,yRect; if (this.Direction==1) yRect=y-rectSize; //底部 else if (this.Direction==2) yRect=y; //顶部 else yRect=y-rectSize/2; //居中 if (this.TextAlign=='left') xRect=x; else if (this.TextAlign=='right') xRect=x-rectSize; else xRect=x-rectSize/2; this.Canvas.fillStyle=this.Color; this.Canvas.fillRect(xRect,yRect,rectSize,rectSize); this.Canvas.fillStyle='rgb(255,255,255)'; this.Canvas.fillText(text,x,y); */ } } } //直线 水平直线 只有1个数据 function ChartStraightLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartStraightLine'; //类名 this.Color="rgb(255,193,37)"; //线段颜色 this.Draw=function() { if (!this.Data || !this.Data.Data) return; if (this.Data.Data.length!=1) return; var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); 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(); 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; } } /* 水平面积 只有1个数据 Data 数据结构 Value, Value2 区间最大最小值 Color=面积的颜色 Title=标题 TitleColor=标题颜色 支持横屏 */ function ChartStraightArea() { this.newMethod = IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartStraightArea'; //类名 this.Color = "rgb(255,193,37)"; //线段颜色 this.Font ='11px 微软雅黑'; this.Draw = function () { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.Data || !this.Data.Data) return; if (this.ChartFrame.IsHScreen===true) { this.HScreenDraw(); return; } var dataWidth = this.ChartFrame.DataWidth; var distanceWidth = this.ChartFrame.DistanceWidth; var chartright = this.ChartBorder.GetRight(); var bottom = this.ChartBorder.GetBottom(); var left = this.ChartBorder.GetLeft(); var xPointCount = this.ChartFrame.XPointCount; var xRight = this.ChartFrame.GetXFromIndex(xPointCount - 1); for(let i in this.Data.Data) { let item=this.Data.Data[i]; if (item==null || isNaN(item.Value) || isNaN(item.Value2)) continue; if (item.Color==null) continue; let valueMax=Math.max(item.Value,item.Value2); let valueMin=Math.min(item.Value,item.Value2); var yTop=this.ChartFrame.GetYFromData(valueMax); var yBottom=this.ChartFrame.GetYFromData(valueMin); this.Canvas.fillStyle = item.Color; this.Canvas.fillRect(ToFixedRect(left), ToFixedRect(yTop), ToFixedRect(xRight - left), ToFixedRect(yBottom - yTop)); if(item.Title && item.TitleColor) { this.Canvas.textAlign = 'right'; this.Canvas.textBaseline = 'middle'; this.Canvas.fillStyle = item.TitleColor; this.Canvas.font = this.Font; let y = yTop + (yBottom - yTop)/2; this.Canvas.fillText(item.Title, xRight, y); } } } this.HScreenDraw=function() { var bottom = this.ChartBorder.GetBottom(); var top=this.ChartBorder.GetTop(); var height=this.ChartBorder.GetHeight(); for(let i in this.Data.Data) { let item=this.Data.Data[i]; if (item==null || isNaN(item.Value) || isNaN(item.Value2)) continue; if (item.Color==null) continue; let valueMax=Math.max(item.Value,item.Value2); let valueMin=Math.min(item.Value,item.Value2); var yTop=this.ChartFrame.GetYFromData(valueMax); var yBottom=this.ChartFrame.GetYFromData(valueMin); this.Canvas.fillStyle = item.Color; this.Canvas.fillRect(ToFixedRect(yBottom), ToFixedRect(top), ToFixedRect(yTop-yBottom),ToFixedRect(height)); if(item.Title && item.TitleColor) { var xText=yTop + (yBottom - yTop)/2; var yText=bottom; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.textAlign = 'right'; this.Canvas.textBaseline = 'middle'; this.Canvas.fillStyle = item.TitleColor; this.Canvas.font = this.Font; this.Canvas.fillText(item.Title, 0, -2); this.Canvas.restore(); } } } 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 (let i in this.Data.Data) { let item = this.Data.Data[i]; if (item==null || isNaN(item.Value) || isNaN(item.Value2)) continue; let valueMax=Math.max(item.Value,item.Value2); let valueMin=Math.min(item.Value,item.Value2); if (range.Max==null) range.Max=valueMax; if (range.Min==null) range.Min=valueMin; if (range.MaxvalueMin) range.Min=valueMin; } return range; } } //分钟线 支持横屏 function ChartMinutePriceLine() { this.newMethod=ChartLine; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartMinutePriceLine'; //类名 this.YClose; this.IsDrawArea=true; //是否画价格面积图 this.AreaColor='rgba(0,191,255,0.1)'; this.SourceData; this.IsShowLead=false; this.LeadData; this.UpColor=g_JSChartResource.UpBarColor; this.DownColor=g_JSChartResource.DownBarColor; this.Draw=function() { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (!this.IsShow) 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 bottom=this.ChartBorder.GetBottomEx(); var left=this.ChartBorder.GetLeftEx(); var data=this.Data; var isBeforeData=false; if (this.SourceData) { data=this.SourceData; isBeforeData=true; } if (this.IsShowLead) this.DrawLead(); var bFirstPoint=true; var ptFirst={}; //第1个点 var drawCount=0; for(var i=data.DataOffset,j=0;i=minuteCount) //上一天的数据和这天地数据线段要断开 { bFirstPoint=true; this.Canvas.stroke(); if (this.IsDrawArea) //画面积 { if (isHScreen) { this.Canvas.lineTo(left,x); this.Canvas.lineTo(left,ptFirst.X); } else { this.Canvas.lineTo(x,bottom); this.Canvas.lineTo(ptFirst.X,bottom); } this.Canvas.fillStyle=this.AreaColor; this.Canvas.fill(); } drawCount=0; } } if (drawCount>0) { this.Canvas.stroke(); if (this.IsDrawArea) //画面积 { if (isHScreen) { this.Canvas.lineTo(left,x); this.Canvas.lineTo(left,ptFirst.X); } else { this.Canvas.lineTo(x,bottom); this.Canvas.lineTo(ptFirst.X,bottom); } this.Canvas.fillStyle=this.AreaColor; this.Canvas.fill(); } } } //画领先指标 this.DrawLead=function() { if (!this.LeadData) return; var isHScreen=(this.ChartFrame.IsHScreen===true); //if (isHScreen) return; //var dataWidth=this.ChartFrame.DataWidth; //var distanceWidth=this.ChartFrame.DistanceWidth; //var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; var minuteCount=this.ChartFrame.MinuteCount; var bottom=this.ChartBorder.GetBottomEx(); var top=this.ChartBorder.GetTopEx(); if (isHScreen===true) top=this.ChartBorder.GetRightEx(); if (xPointCount>minuteCount) return; var aryLead=[]; //{X: Value:} var max=null, min=null; var yCenter=this.ChartFrame.GetYFromData(this.YClose); var leadHeight=(yCenter-top)/3; var data=this.LeadData; for(var i=data.DataOffset,j=0;ivalue) min=value; aryLead.push({X:x, Value:value}) } if (aryLead.length<=0) return; var maxValue=Math.max(Math.abs(max),Math.abs(min)); for(var i in aryLead) { var item=aryLead[i]; if (item.Value>0) this.Canvas.strokeStyle=this.UpColor; else this.Canvas.strokeStyle=this.DownColor; var y=yCenter-(item.Value*leadHeight/maxValue); var x=ToFixedPoint(item.X); this.Canvas.beginPath(); if (isHScreen===true) { this.Canvas.moveTo(yCenter,x); this.Canvas.lineTo(y,x); } else { this.Canvas.moveTo(x,yCenter); this.Canvas.lineTo(x,y); } this.Canvas.stroke(); } } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; if (this.YClose==null) return range; if (!this.IsShow) return range; range.Min=this.YClose; range.Max=this.YClose; var data=this.Data; var isBeforeData=false; if (this.SourceData) { data=this.SourceData; isBeforeData=true; } for(var i=data.DataOffset,j=0;ivalue) range.Min=value; } if (range.Max==this.YClose && range.Min==this.YClose) { range.Max=this.YClose+this.YClose*0.1; range.Min=this.YClose-this.YClose*0.1; return range; } var distance=Math.max(Math.abs(this.YClose-range.Max),Math.abs(this.YClose-range.Min)); range.Max=this.YClose+distance; range.Min=this.YClose-distance; return range; } } //分钟线叠加 支持横屏 function ChartOverlayMinutePriceLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Color="rgb(65,105,225)"; this.MainData; //主图数据 this.MainYClose; //主图股票的前收盘价 this.SourceData; //原始数据 this.BeforeDataCount=0; this.IsBeforeData=false; this.ClassName="ChartOverlayMinutePriceLine"; this.Title; this.Symbol; //叠加的股票代码 this.YClose; //叠加的股票前收盘 this.Status=OVERLAY_STATUS_ID.STATUS_NONE_ID; this.Draw=function() { if (!this.Data) return; 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; var xOffset=0; if (this.IsBeforeData) xOffset=1; //集合竞价模式从第2个数据开始 第1个数据是9:25数据 for(var i=this.Data.DataOffset+xOffset,j=0;i=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;ivalue) 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; //console.log(`[ChartOverlayMinutePriceLine::GetMaxMin] max=${range.Max} min=${range.Min}`); return range; } } //分钟信息地雷 支持横屏 function ChartMinuteInfo() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName="ChartMinuteInfo"; this.Data=new Map() //Map key=date-time, value=[{Date, Time, Title, Type, ID:}] this.SourceData; this.ChartMinutePrice; this.YClose; this.HQChartBorder; this.TextColor=g_JSChartResource.MinuteInfo.TextColor; this.Font=g_JSChartResource.MinuteInfo.Font; this.PointColor=g_JSChartResource.MinuteInfo.PointColor; this.LineColor=g_JSChartResource.MinuteInfo.LineColor; this.TextBGColor=g_JSChartResource.MinuteInfo.TextBGColor; this.PixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 this.TextHeight=20; this.TextRectCache=[]; this.InfoDrawCache=[]; this.FrameBottom; this.FrameTop; this.FrameLeft; this.FrameRight; this.YOffset=5; this.IsHScreen=false; this.IsDrawFull=false; //是否全屏画 this.SetOption=function(option) { if (option.TextColor) this.TextColor=option.TextColor; if (option.TextBGColor) this.TextBGColor=option.TextBGColor; if (option.Font) this.Font=option.Font; if (option.PointColor) this.PointColor=option.PointColor; if (option.LineColor) this.LineColor=option.LineColor; if (option.TextHeight>0) this.TextHeight=option.TextHeight; if (option.IsDrawFull==true) this.IsDrawFull=true; } this.Draw=function() { if (!this.ChartMinutePrice) return; if (!this.Data || this.Data.size<=0) return; this.TextRectCache=[]; this.InfoDrawCache=[]; this.PixelTatio=GetDevicePixelRatio(); this.YOffset=5*this.PixelTatio; this.IsHScreen=(this.ChartFrame.IsHScreen===true); var xPointCount=this.ChartFrame.XPointCount; var minuteCount=this.ChartFrame.MinuteCount; this.FrameBottom=this.ChartBorder.GetBottom(); if (this.IsDrawFull && this.HQChartBorder) this.FrameBottom=this.HQChartBorder.GetBottom(); this.FrameTop=this.ChartBorder.GetTop(); this.FrameLeft=this.ChartBorder.GetLeft(); this.FrameRight=this.ChartBorder.GetRight(); if (this.IsHScreen) { this.FrameRight=this.ChartBorder.GetBottom(); this.FrameLeft=this.ChartBorder.GetTop(); this.FrameBottom=this.ChartBorder.GetLeft(); this.FrameTop=this.ChartBorder.GetRight(); } this.YClose=this.ChartMinutePrice.YClose; var data=this.ChartMinutePrice.Data; var isBeforeData=false; if (this.ChartMinutePrice.SourceData) { data=this.ChartMinutePrice.SourceData; isBeforeData=true; } for(var i=data.DataOffset,j=0;ithis.YClose) xData.X=xData.X.reverse(); var rtBorder={X:null, Y:y, Width:textWidth,Height:textHeight}; if (!isDrawLeft) rtBorder.Y-=rtBorder.Height; this.FixHScreenTextRect(rtBorder,xData); var InfoDrawItem={ Border:rtBorder, Start:{X:x,Y:y}, IsLeft:isDrawLeft, Title:showItem.Title }; this.InfoDrawCache.push(InfoDrawItem); this.TextRectCache.push(rtBorder); } this.DrawInfoLines=function(item) { var rtBorder=item.Border; var isDrawLeft=item.IsLeft; this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ToFixedPoint(item.Start.X),item.Start.Y); if (isDrawLeft) { this.Canvas.lineTo(ToFixedPoint(item.Start.X),rtBorder.Y); } else { if (this.IsHScreen) this.Canvas.lineTo(rtBorder.X,rtBorder.Y+rtBorder.Height); else this.Canvas.lineTo(ToFixedPoint(item.Start.X),rtBorder.Y); } this.Canvas.stroke(); this.Canvas.fillStyle = this.PointColor; this.Canvas.beginPath(); this.Canvas.arc(item.Start.X,item.Start.Y, 5, 0, 2 * Math.PI); this.Canvas.closePath(); this.Canvas.fill(); } this.DrawInfoText=function(item) { var rtBorder=item.Border; var x=rtBorder.X, y=rtBorder.Y; this.Canvas.fillStyle=this.TextBGColor; this.Canvas.fillRect(x, y, rtBorder.Width,rtBorder.Height); this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.rect(x,y,rtBorder.Width,rtBorder.Height); this.Canvas.stroke(); if (this.IsHScreen) { this.Canvas.save(); this.Canvas.translate(rtBorder.X,rtBorder.Y); this.Canvas.rotate(90 * Math.PI / 180); x=0;y=0; } this.Canvas.textAlign = 'left' this.Canvas.textBaseline = 'middle'; this.Canvas.fillStyle = this.TextColor; this.Canvas.font = this.Font; if (this.IsHScreen) this.Canvas.fillText(item.Title, x+2*this.PixelTatio, y-rtBorder.Width/2); else this.Canvas.fillText(item.Title, x+2*this.PixelTatio, y+rtBorder.Height/2); if (this.IsHScreen) this.Canvas.restore(); } this.FixTextRect=function(rect,yData) { for(var k in yData.Y) { var yItem=yData.Y[k]; rect.Y=yItem.Value; var y; for(var j=0;j<10;++j) { var isOverlap=false; for(var i in this.TextRectCache) { var item=this.TextRectCache[i]; if (this.IsOverlap(item, rect)) { isOverlap=true; break; } } if (isOverlap==false) return; y=rect.Y; y+=yItem.Offset; if (y+rect.Height>this.FrameBottom || ythis.FrameTop) break; rect.X=x; } } } this.IsOverlap=function(rc1, rc2) { if (rc1.X + rc1.Width > rc2.X &&rc2.X + rc2.Width > rc1.X &&rc1.Y + rc1.Height > rc2.Y &&rc2.Y + rc2.Height > rc1.Y) return true; else return false; } this.GetMaxMin=function() { var range={Min:null, Max:null}; return range; } } //MACD森林线 支持横屏 function ChartMACD() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName="ChartMACD"; this.UpColor=g_JSChartResource.UpBarColor; this.DownColor=g_JSChartResource.DownBarColor; this.Draw=function() { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (this.ChartFrame.IsHScreen===true) { this.HScreenDraw(); return; } var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; var lockRect=this.GetLockRect(); if (lockRect) chartright=lockRect.Left; var bFirstPoint=true; var drawCount=0; var yBottom=this.ChartFrame.GetYFromData(0); for(var i=this.Data.DataOffset,j=0;ichartright) break; var xFix=parseInt(x.toString())+0.5; //毛边修正 this.Canvas.beginPath(); this.Canvas.moveTo(xFix,yBottom); this.Canvas.lineTo(xFix,y); if (value>=0) this.Canvas.strokeStyle=this.UpColor; else this.Canvas.strokeStyle=this.DownColor; this.Canvas.stroke(); this.Canvas.closePath(); } } this.HScreenDraw=function() { var chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; var lockRect=this.GetLockRect(); if (lockRect) chartright=lockRect.Top; var yBottom=this.ChartFrame.GetYFromData(0); for(var i=this.Data.DataOffset,j=0;ichartright) break; this.Canvas.beginPath(); this.Canvas.moveTo(yBottom,ToFixedPoint(x)); this.Canvas.lineTo(y,ToFixedPoint(x)); if (value>=0) this.Canvas.strokeStyle=this.UpColor; else this.Canvas.strokeStyle=this.DownColor; this.Canvas.stroke(); this.Canvas.closePath(); } } } //柱子 function ChartBar() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName="ChartBar"; this.UpBarColor=g_JSChartResource.UpBarColor; this.DownBarColor=g_JSChartResource.DownBarColor; 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 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;ichartright) break; var x=this.ChartFrame.GetXFromIndex(j); var y=this.ChartFrame.GetYFromData(value); if (value>0) this.Canvas.fillStyle=this.UpBarColor; else this.Canvas.fillStyle=this.DownBarColor; //高度调整为整数 var 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;ichartright) 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(); } } } 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 1) { this.Canvas.save(); this.Canvas.beginPath(); for (var i = 0; i < firstlinePoints.length; ++i) { if (i == 0) this.Canvas.moveTo(firstlinePoints[i].x, firstlinePoints[i].y); else this.Canvas.lineTo(firstlinePoints[i].x, firstlinePoints[i].y); } for (var j = secondlinePoints.length-1; j >= 0; --j) { this.Canvas.lineTo(secondlinePoints[j].x, secondlinePoints[j].y); } this.Canvas.closePath(); this.Canvas.clip(); this.Canvas.beginPath(); this.Canvas.moveTo(firstlinePoints[0].x, this.ChartBorder.GetBottom()); for (var i = 0; i < firstlinePoints.length; ++i) { this.Canvas.lineTo(firstlinePoints[i].x, firstlinePoints[i].y); } this.Canvas.lineTo(firstlinePoints[firstlinePoints.length-1].x, this.ChartBorder.GetBottom()); this.Canvas.closePath(); this.Canvas.fillStyle = this.FirstColor; this.Canvas.fill(); this.Canvas.beginPath(); this.Canvas.moveTo(secondlinePoints[0].x, this.ChartBorder.GetBottom()); for (var i = 0; i < secondlinePoints.length; ++i) { this.Canvas.lineTo(secondlinePoints[i].x, secondlinePoints[i].y); } this.Canvas.lineTo(secondlinePoints[secondlinePoints.length-1].x, this.ChartBorder.GetBottom()); this.Canvas.closePath(); this.Canvas.fillStyle = this.SecondColor; this.Canvas.fill(); this.Canvas.restore(); } } this.GetMaxMin=function() { var xPointCount=this.ChartFrame.XPointCount; var range={}; range.Min=null; range.Max=null; for(var i=this.Data.DataOffset,j=0;ivalue.Value2?value.Value:value.Value2; var minData = value.Value minData) range.Min = minData; } return range; } } // 通道面积图 支持横屏 function ChartChannel() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.IsDrawFirst = true; this.ClassName="ChartChannel"; this.IsHScreen=false; //是否是横屏 this.PointCount=0; this.DataWidth=0; this.DistanceWidth=0; this.ChartRight=0; //可以绘制的最右边 this.LineColor='RGB(255,0,0)'; this.LineDotted=[3,3]; this.AreaColor='RGB(255,222,173)'; this.LineWidth=1; this.CalculateData=function() //把数据通过nul值分割开, 并计算坐标 { var data=[]; var lineData=[]; for(var i=this.Data.DataOffset,j=0;i0) { data.push(lineData); lineData=[]; //创建新的一组数据 } continue; } var x=this.ChartFrame.GetXFromIndex(j); if (x>this.ChartRight) break; var y=this.ChartFrame.GetYFromData(item.Value); var y2=this.ChartFrame.GetYFromData(item.Value2); lineData.push({X:x, Y:y,Y2:y2}); } if (lineData.length>0) data.push(lineData); return data; } this.DrawArea=function(lineData) { if (lineData.length<=0) return; this.Canvas.beginPath(); var drawCount=0; var firstItem=lineData[0]; if (this.IsHScreen) this.Canvas.moveTo(firstItem.Y,firstItem.X); else this.Canvas.moveTo(firstItem.X,firstItem.Y); for(var i=1;i=0;--i) { var item=lineData[i]; if (this.IsHScreen) this.Canvas.lineTo(item.Y2,item.X); else this.Canvas.lineTo(item.X,item.Y2); ++drawCount; } this.Canvas.closePath(); this.Canvas.fillStyle = this.AreaColor; this.Canvas.fill(); } this.DrawLine=function(lineData) { this.Canvas.strokeStyle=this.LineColor; for(var k=0;k<2;++k) { var bFirstPoint=true; var drawCount=0; for(var i=0;i0) this.Canvas.stroke(); } } this.Draw=function() { if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } this.IsHScreen=(this.ChartFrame.IsHScreen===true); this.PointCount=this.ChartFrame.XPointCount; this.DataWidth=this.ChartFrame.DataWidth; this.DistanceWidth=this.ChartFrame.DistanceWidth; if (this.IsHScreen) this.ChartRight=this.ChartBorder.GetBottom(); else this.ChartRight=this.ChartBorder.GetRight(); var drawData=this.CalculateData(); if (!drawData || drawData.length<=0) return; this.Canvas.save(); this.Canvas.lineWidth=this.LineWidth*GetDevicePixelRatio(); this.Canvas.setLineDash(this.LineDotted); //虚线 for(var i=0;ivalue.Value2?value.Value:value.Value2; var minData = value.Value minData) range.Min = minData; } return range; } } //填充背景 TODO:横屏 function ChartBackground() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Color=null; this.ColorAngle=0; //0 竖向 1 横向 this.Draw=function() { if (!this.IsShow) return; if (!this.Color) return; if (this.Color.length<=0) return; if (this.Color.length==2) { if (this.ColorAngle==0) { var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() }; var ptEnd={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetBottomEx() }; } else { var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() }; var ptEnd={ X:this.ChartBorder.GetRight(), Y:this.ChartBorder.GetTopEx() }; } let gradient = this.Canvas.createLinearGradient(ptStart.X,ptStart.Y, ptEnd.X,ptEnd.Y); gradient.addColorStop(0, this.Color[0]); gradient.addColorStop(1, this.Color[1]); this.Canvas.fillStyle=gradient; } else if (this.Color.length==1) { this.Canvas.fillStyle=this.Color[0]; } else { return; } var left=this.ChartBorder.GetLeft(); var top=this.ChartBorder.GetTopEx(); var width=this.ChartBorder.GetWidth(); var height=this.ChartBorder.GetHeightEx(); this.Canvas.fillRect(left, top,width, height); } } //画矩形 function ChartRectangle() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Color=[]; this.Rect; this.BorderColor=g_JSChartResource.FrameBorderPen; this.Draw=function() { if (!this.IsShow) return; if (!this.Color || !this.Rect) return; if (this.Color.length<=0) return; this.Canvas.strokeStyle=this.BorderColor; var bFill=false; if (this.Color.length==2) { /* TODO 渐变下次做吧 if (this.ColorAngle==0) { var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() }; var ptEnd={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetBottomEx() }; } else { var ptStart={ X:this.ChartBorder.GetLeft(), Y:this.ChartBorder.GetTopEx() }; var ptEnd={ X:this.ChartBorder.GetRight(), Y:this.ChartBorder.GetTopEx() }; } let gradient = this.Canvas.createLinearGradient(ptStart.X,ptStart.Y, ptEnd.X,ptEnd.Y); gradient.addColorStop(0, this.Color[0]); gradient.addColorStop(1, this.Color[1]); this.Canvas.fillStyle=gradient; */ this.Canvas.fillStyle=this.Color[0]; bFill=true; } else if (this.Color.length==1) { if (this.Color[0]) { this.Canvas.fillStyle=this.Color[0]; bFill=true; } } else { return; } var chartWidth=this.ChartBorder.GetWidth(); var chartHeight=this.ChartBorder.GetHeightEx(); var left=this.Rect.Left/1000*chartWidth; var top=this.Rect.Top/1000*chartHeight; var right=this.Rect.Right/1000*chartWidth; var bottom=this.Rect.Bottom/1000*chartHeight; left=this.ChartBorder.GetLeft()+left top=this.ChartBorder.GetTopEx()+top; right=this.ChartBorder.GetLeft()+right; bottom=this.ChartBorder.GetTopEx()+bottom; var width=Math.abs(left-right); var height=Math.abs(top-bottom); if (bFill) this.Canvas.fillRect(left, top,width, height); this.Canvas.rect(ToFixedPoint(left), ToFixedPoint(top),ToFixedRect(width), ToFixedRect(height)); this.Canvas.stroke(); } } // 文字+线段输出 function ChartTextLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Text; //Text=内容 Color this.Line; //Type=线段类型 0=不画 1=直线 2=虚线, Color this.Price; this.Draw=function() { if (!this.IsShow) return; if (!this.Text || !this.Line || !IFrameSplitOperator.IsNumber(this.Price)) return; this.IsHScreen=(this.ChartFrame.IsHScreen===true); var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var bottom=this.ChartBorder.GetBottomEx(); var top=this.ChartBorder.GetTopEx(); var y=this.ChartFrame.GetYFromData(this.Price); var textWidth=0; if (this.Text.Title) { var x=left+2*GetDevicePixelRatio(); var yText=y; this.Canvas.textAlign = 'left'; this.Canvas.textBaseline = 'middle'; var offsetY=8*GetDevicePixelRatio(); if (y-offsetYbottom) { this.Canvas.textBaseline='bottom'; yText=bottom; } this.Canvas.fillStyle = this.Text.Color; this.Canvas.font = this.Text.Font; this.Canvas.fillText(this.Text.Title, x, yText); textWidth=this.Canvas.measureText(this.Text.Title).width+4*GetDevicePixelRatio(); } if (this.Line.Type>0) { if (this.Line.Type==2) //虚线 { this.Canvas.save(); this.Canvas.setLineDash([3,5]); //虚线 } var x=left+textWidth; this.Canvas.strokeStyle=this.Line.Color; this.Canvas.beginPath(); this.Canvas.moveTo(x,ToFixedPoint(y)); this.Canvas.lineTo(right,ToFixedPoint(y)); this.Canvas.stroke(); if (this.Line.Type==2) { this.Canvas.restore(); } } } this.GetMaxMin=function() { var range={Min:null, Max:null}; if (IFrameSplitOperator.IsNumber(this.Price)) { range.Min=this.Price; range.Max=this.Price; } return range; } } // 线段集合 支持横屏 function ChartMultiLine() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Lines=[]; // [ {Point:[ {Index, Value }, ], Color: }, ] this.IsHScreen=false; this.Draw=function() { if (!this.IsShow) return; if (!this.Data || this.Data.length<=0) return; this.IsHScreen=(this.ChartFrame.IsHScreen===true); var xPointCount=this.ChartFrame.XPointCount; var offset=this.Data.DataOffset; var drawLines=[]; for(var i in this.Lines) { var line=this.Lines[i]; var drawPoints={ Point:[], Color:line.Color }; for(var j in line.Point) { var point=line.Point[j]; if (!IFrameSplitOperator.IsNumber(point.Index)) continue; var index=point.Index-offset; if (index>=0 && index=2) drawLines.push(drawPoints) } for(var i in drawLines) { var item=drawLines[i]; this.DrawLine(item); } } this.DrawLine=function(line) { this.Canvas.strokeStyle=line.Color; for(var i in line.Point) { var item=line.Point[i]; if (i==0) { this.Canvas.beginPath(); if (this.IsHScreen) this.Canvas.moveTo(item.Y,item.X); else this.Canvas.moveTo(item.X,item.Y); } else { if (this.IsHScreen) this.Canvas.lineTo(item.Y,item.X); else this.Canvas.lineTo(item.X,item.Y); } } this.Canvas.stroke(); } this.GetMaxMin=function() { var range={ Min:null, Max:null }; var xPointCount=this.ChartFrame.XPointCount; var start=this.Data.DataOffset; var end=start+xPointCount; for(var i in this.Lines) { var line=this.Lines[i]; for(var j in line.Point) { var point=line.Point[j]; if (point.Index>=start && point.Indexpoint.Value) range.Min=point.Value; } } } return range; } } // 多文本集合 function ChartMultiText() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Texts=[]; //[ {Index:, Value:, Text:, Color:, Font: , Baseline:} ] this.Font=g_JSChartResource.DefaultTextFont; this.Color=g_JSChartResource.DefaultTextColor; this.Draw=function() { if (!this.IsShow) return; if (!this.Data || this.Data.length<=0) return; if (!this.Texts) return; var xPointCount=this.ChartFrame.XPointCount; var offset=this.Data.DataOffset; var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); for(var i in this.Texts) { var item=this.Texts[i]; if (!item.Text) continue; if (!IFrameSplitOperator.IsNumber(item.Index)) continue; var index=item.Index-offset; if (index>=0 && index=right) { this.Canvas.textAlign='right'; x=right; } else if (x-textWidth/2=start && item.Indexitem.Value) range.Min=item.Value; } } return range; } } // 图标集合 支持横屏 function ChartMultiSVGIcon() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Icon; //[ {Index:, Value:, Symbol:, Color:, Baseline:} ] this.Family; this.Color=g_JSChartResource.DefaultTextColor; this.IsHScreen=false; this.Draw=function() { if (!this.IsShow) return; if (!this.Data || this.Data.length<=0) return; if (!this.Family || !this.Icon) return; this.IsHScreen=(this.ChartFrame.IsHScreen===true); var xPointCount=this.ChartFrame.XPointCount; var offset=this.Data.DataOffset; var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); this.DataWidth=this.ChartFrame.DataWidth; this.DistanceWidth=this.ChartFrame.DistanceWidth; if (this.IsHScreen) { left=this.ChartBorder.GetTop(); right=this.ChartBorder.GetBottom(); } var fontSize=(this.DataWidth+this.DistanceWidth)-2; if (fontSize<8) fontSize=8; this.Canvas.font=fontSize+'px '+this.Family; for(var i in this.Icon) { var item=this.Icon[i]; if (!IFrameSplitOperator.IsNumber(item.Index)) continue; var index=item.Index-offset; if (index>=0 && index=right) { this.Canvas.textAlign='right'; x+=this.DataWidth/2; } else if (x-textWidth/2=start && item.Indexitem.Value) range.Min=item.Value; } } return range; } } //锁 支持横屏 function ChartLock() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ClassName="ChartLock"; this.WidthDiv = 0.2; // 框子宽度占比 this.LockCount = 20; // 锁最新的几个数据 this.BGColor = g_JSChartResource.LockBGColor; this.TextColor = g_JSChartResource.LockTextColor; this.Font = g_JSChartResource.DefaultTextFont; this.Title = '🔒开通权限'; this.LockRect=null; //上锁区域 this.LockID; //锁ID this.Callback; //回调 this.IndexName; //指标名字 this.MinWidth=null; //最小宽度 this.Draw=function(isDraw) { this.LockRect=null; if (this.NotSupportMessage) { this.DrawNotSupportmessage(); return; } if (this.ChartFrame.IsHScreen===true) { this.HScreenDraw(isDraw); return; } var xOffset = this.ChartBorder.GetRight(); var lOffsetWidth = 0; if (this.ChartFrame.Data != null) { var dataWidth=this.ChartFrame.DataWidth; var distanceWidth=this.ChartFrame.DistanceWidth; xOffset=this.ChartBorder.GetLeft()+distanceWidth/2.0+2.0; var chartright=this.ChartBorder.GetRight(); var xPointCount=this.ChartFrame.XPointCount; for(var i=this.ChartFrame.Data.DataOffset,j=0;ichartright) break; } lOffsetWidth = (dataWidth + distanceWidth) * this.LockCount; } if (lOffsetWidth == 0) { lOffsetWidth = (xOffset - this.ChartBorder.GetLeft()) * this.WidthDiv; } var lLeft = xOffset - lOffsetWidth; if (lLeft < this.ChartBorder.GetLeft()) lLeft = this.ChartBorder.GetLeft(); var lHeight = this.ChartBorder.GetBottom() - this.ChartBorder.GetTop(); var lWidth = this.ChartBorder.GetRight() - lLeft; if (this.MinWidth>10 && lWidthchartright) break; } lOffsetWidth = (dataWidth + distanceWidth) * this.LockCount; } if (lOffsetWidth == 0) { lOffsetWidth = (xOffset - this.ChartBorder.GetTop()) * this.WidthDiv; } var lLeft = xOffset - lOffsetWidth; if (lLeft < this.ChartBorder.GetTop()) lLeft = this.ChartBorder.GetTop(); var lHeight = this.ChartBorder.GetRight()-this.ChartBorder.GetLeft(); var lWidth = this.ChartBorder.GetBottom() - lLeft; this.Canvas.fillStyle = this.BGColor; this.Canvas.fillRect(this.ChartBorder.GetLeft(), lLeft,lHeight,lWidth); var xCenter = this.ChartBorder.GetLeft() + lHeight / 2; var yCenter = lLeft + lWidth / 2; this.Canvas.save(); this.Canvas.translate(xCenter, yCenter); this.Canvas.rotate(90 * Math.PI / 180); this.Canvas.textAlign = 'center'; this.Canvas.textBaseline = 'middle'; this.Canvas.fillStyle = this.TextColor; this.Canvas.font = this.Font; this.Canvas.fillText(this.Title, 0, 0); this.Canvas.restore(); this.LockRect={Left:this.ChartBorder.GetLeft(),Top:lLeft,Width:lHeight,Heigh:lWidth}; //保存上锁区域 } //x,y是否在上锁区域 this.GetTooltipData=function(x,y,tooltip) { if (this.LockRect==null) return false; this.Canvas.beginPath(); this.Canvas.rect(this.LockRect.Left,this.LockRect.Top,this.LockRect.Width,this.LockRect.Heigh); if (this.Canvas.isPointInPath(x,y)) { tooltip.Data={ ID:this.LockID, Callback:this.Callback, IndexName:this.IndexName }; tooltip.ChartPaint=this; return true; } return false; } } //买卖盘 function ChartBuySell() { this.newMethod=ChartSingleText; //派生 this.newMethod(); delete this.newMethod; this.ClassName="ChartBuySell"; this.TextFont=g_JSChartResource.KLineTrain.Font; //"bold 14px arial"; //买卖信息字体 this.LastDataIcon=g_JSChartResource.KLineTrain.LastDataIcon; //{Color:'rgb(0,0,205)',Text:'↓'}; this.BuyIcon=g_JSChartResource.KLineTrain.BuyIcon; //{Color:'rgb(0,0,205)',Text:'B'}; this.SellIcon=g_JSChartResource.KLineTrain.SellIcon; //{Color:'rgb(0,0,205)',Text:'S'}; this.BuySellData=new Map(); //{Date:日期, Op:买/卖 0=buy 1=sell} this.LastData={}; //当前屏最后一个数据 this.IconFont=g_JSChartResource.KLineTrain.IconFont; this.Draw=function() { 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===true) chartright=this.ChartBorder.GetBottom(); var xPointCount=this.ChartFrame.XPointCount; if (this.IconFont) { var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 var iconSize=dataWidth+distanceWidth; var minIconSize=18*pixelTatio; if (iconSizechartright) break; this.LastData={ID:j,Data:value}; if (!this.BuySellData.has(value.Date)) continue; var bsItem=this.BuySellData.get(value.Date); var x=this.ChartFrame.GetXFromIndex(j); var yHigh=this.ChartFrame.GetYFromData(value.High); var yLow=this.ChartFrame.GetYFromData(value.Low); if (bsItem.Op==0) //买 标识在最低价上 { this.Canvas.textAlign='center'; this.Canvas.textBaseline='top'; if (this.IconFont) { this.Canvas.fillStyle=this.IconFont.Buy.Color this.DrawText(this.IconFont.Buy.Text,x,yLow,isHScreen); } else { this.Canvas.fillStyle=this.BuyIcon.Color; this.DrawText(this.BuyIcon.Text,x,yLow,isHScreen); } } else //卖 标识在最高价上 { this.Canvas.textAlign='center'; this.Canvas.textBaseline='bottom'; if (this.IconFont) { this.Canvas.fillStyle=this.IconFont.Sell.Color this.DrawText(this.IconFont.Sell.Text,x,yHigh,isHScreen); } else { this.Canvas.fillStyle=this.SellIcon.Color; this.DrawText(this.SellIcon.Text,x,yHigh,isHScreen); } } } //最后一个位置 var x=this.ChartFrame.GetXFromIndex(this.LastData.ID); var yHigh=this.ChartFrame.GetYFromData(this.LastData.Data.High); this.Canvas.textAlign='center'; this.Canvas.textBaseline='bottom'; if (this.IconFont) { this.Canvas.fillStyle=this.IconFont.Last.Color this.DrawText(this.IconFont.Last.Text,x,yHigh,isHScreen); } else { this.Canvas.fillStyle=this.LastDataIcon.Color; this.Canvas.font=this.TextFont; this.DrawText(this.LastDataIcon.Text,x,yHigh,isHScreen); } } } /* 饼图 */ function ChartPie() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Radius = 100; //半径默认值 this.Distance = 30; //指示线超出圆饼的距离 this.txtLine = 20; // 文本下划线 this.paddingX = 20 / 3;// 设置文本的移动 // return; this.Draw=function() { if (!this.Data || !this.Data.Data || !(this.Data.Data.length>0)) return this.DrawEmptyData(); let left=this.ChartBorder.GetLeft(); let right=this.ChartBorder.GetRight(); let top=this.ChartBorder.GetTop(); let bottom=this.ChartBorder.GetBottom(); let width=this.ChartBorder.GetWidth(); let height=this.ChartBorder.GetHeight(); if(isNaN(this.Radius)){ let str = this.Radius.replace("%",""); str = str/100; if(width >= height){ this.Radius = str*height; } if(width < height) this.Radius = str*width; } this.Canvas.save(); this.Canvas.translate(width/2,height/2); let totalValue=0; //求和 for(let i in this.Data.Data) { totalValue += this.Data.Data[i].Value; } let start = 0; let end = 0; //画饼图 for(let i in this.Data.Data) { let item =this.Data.Data[i]; let rate=(item.Value/totalValue).toFixed(2); //占比 //console.log('[ChartPie::Draw]', i, rate, item); // 绘制扇形 this.Canvas.beginPath(); this.Canvas.moveTo(0,0); end += rate*2*Math.PI;//终止角度 this.Canvas.strokeStyle = "white"; this.Canvas.fillStyle = item.Color; this.Canvas.arc(0,0,this.Radius,start,end); this.Canvas.fill(); this.Canvas.closePath(); this.Canvas.stroke(); // 绘制直线 this.Canvas.beginPath(); this.Canvas.strokeStyle = item.Color; this.Canvas.moveTo(0,0); let x = (this.Radius + this.Distance)*Math.cos(end- (end-start)/2); let y = (this.Radius + this.Distance)*Math.sin(end - (end-start)/2); this.Canvas.lineTo(x,y); // console.log(x,y,"xy") // 绘制横线 let txtLine = this.txtLine; let paddingX = this.paddingX; this.Canvas.textAlign = 'left'; if( end - (end-start)/2 < 1.5*Math.PI && end - (end-start)/2 > 0.5*Math.PI ){ txtLine = - this.txtLine; paddingX = - this.paddingX; this.Canvas.textAlign = 'right'; } this.Canvas.lineTo( x + txtLine, y ); this.Canvas.stroke(); // 写文字 if(item.Text){ this.Canvas.fillText( item.Text, x + txtLine + paddingX, y ); }else{ let text = `${item.Name}:${item.Value}`; this.Canvas.fillText( text, x + txtLine + paddingX, y ); } start += rate*2*Math.PI;//起始角度 } this.Canvas.restore(); } //空数据 this.DrawEmptyData=function() { console.log('[ChartPie::DrawEmptyData]') } } /* 雷达图 */ function ChartRadar() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.BorderPoint=[]; //边框点 this.DataPoint=[]; //数据点 this.CenterPoint={}; this.StartAngle=0; this.Color='rgb(198,198,198)'; this.AreaColor='rgba(242,154,118,0.4)'; //面积图颜色 this.AreaLineColor='rgb(242,154,118)'; this.TitleFont=24*GetDevicePixelRatio()+'px 微软雅黑'; this.TitleColor='rgb(102,102,102)'; this.BGColor = ['rgb(255,255,255)', 'rgb(224,224,224)']//背景色 this.DrawBorder=function() //画边框 { if (this.BorderPoint.length<=0) return; this.Canvas.font=this.TitleFont; this.Canvas.strokeStyle = this.Color; const aryBorder=[1,0.8,0.6,0.4,0.2]; for (let j in aryBorder) { var rate = aryBorder[j]; var isFirstDraw=true; for(let i in this.BorderPoint) { var item=this.BorderPoint[i]; item.X = this.CenterPoint.X + item.Radius * Math.cos(item.Angle * Math.PI / 180) * rate; item.Y = this.CenterPoint.Y + item.Radius * Math.sin(item.Angle * Math.PI / 180) * rate; if (isFirstDraw) { this.Canvas.beginPath(); this.Canvas.moveTo(item.X,item.Y); isFirstDraw=false; } else { this.Canvas.lineTo(item.X,item.Y); } } this.Canvas.closePath(); this.Canvas.stroke(); this.Canvas.fillStyle = this.BGColor[j%2==0?0:1]; this.Canvas.fill(); } this.Canvas.beginPath(); for(let i in this.BorderPoint) { var item=this.BorderPoint[i]; item.X = this.CenterPoint.X + item.Radius * Math.cos(item.Angle * Math.PI / 180); item.Y = this.CenterPoint.Y + item.Radius * Math.sin(item.Angle * Math.PI / 180); this.Canvas.moveTo(this.CenterPoint.X,this.CenterPoint.Y); this.Canvas.lineTo(item.X,item.Y); this.DrawText(item); } this.Canvas.stroke(); } this.DrawArea=function() { if (!this.DataPoint || this.DataPoint.length<=0) return; this.Canvas.fillStyle = this.AreaColor; this.Canvas.strokeStyle = this.AreaLineColor; this.Canvas.beginPath(); var isFirstDraw=true; for(let i in this.DataPoint) { var item=this.DataPoint[i]; if (isFirstDraw) { this.Canvas.beginPath(); this.Canvas.moveTo(item.X,item.Y); isFirstDraw=false; } else { this.Canvas.lineTo(item.X,item.Y); } } this.Canvas.closePath(); this.Canvas.fill(); this.Canvas.stroke(); } this.DrawText=function(item) { if (!item.Text) return; //console.log(item.Text, item.Angle); this.Canvas.fillStyle = this.TitleColor; var xText = item.X, yText = item.Y; //显示每个角度的位置 if (item.Angle > 0 && item.Angle < 45) { this.Canvas.textAlign = 'left'; this.Canvas.textBaseline = 'middle'; xText += 2; } else if (item.Angle >= 0 && item.Angle < 90) { this.Canvas.textAlign = 'left'; this.Canvas.textBaseline = 'top'; xText += 2; } else if (item.Angle >= 90 && item.Angle < 135) { this.Canvas.textAlign = 'right'; this.Canvas.textBaseline = 'top'; xText -= 2; } else if (item.Angle >= 135 && item.Angle < 180) { this.Canvas.textAlign = 'right'; this.Canvas.textBaseline = 'top'; xText -= 2; } else if (item.Angle >= 180 && item.Angle < 225) { this.Canvas.textAlign = 'right'; this.Canvas.textBaseline = 'middle'; xText -= 2; } else if (item.Angle >= 225 && item.Angle <= 270) { this.Canvas.textAlign = 'center'; this.Canvas.textBaseline = 'bottom'; } else if (item.Angle > 270 && item.Angle < 315) { this.Canvas.textAlign = 'left'; this.Canvas.textBaseline = 'bottom'; xText += 2; } else { this.Canvas.textAlign = 'left'; this.Canvas.textBaseline = 'middle'; xText += 2; } this.Canvas.fillText(item.Text, xText, yText); } this.Draw=function() { this.BorderPoint=[]; this.DataPoint=[]; this.CenterPoint={}; if (!this.Data || !this.Data.Data || !(this.Data.Data.length>0)) this.CalculatePoints(null); else this.CalculatePoints(this.Data.Data); this.DrawBorder(); this.DrawArea(); } this.CalculatePoints=function(data) { let left=this.ChartBorder.GetLeft(); let right=this.ChartBorder.GetRight(); let top=this.ChartBorder.GetTop(); let bottom=this.ChartBorder.GetBottom(); let width=this.ChartBorder.GetWidth(); let height=this.ChartBorder.GetHeight(); let ptCenter={X:left+width/2, Y:top+height/2}; //中心点 let radius=Math.min(width/2,height/2)-2 //半径 let count=Math.max(5,data?data.length:0); let averageAngle=360/count; for(let i=0;i=1) value=1; var dataRadius=radius*value; ptData.X=ptCenter.X+dataRadius*Math.cos(angle*Math.PI/180); ptData.Y=ptCenter.Y+dataRadius*Math.sin(angle*Math.PI/180); } this.DataPoint.push(ptData); } this.BorderPoint.push(ptBorder); } this.CenterPoint=ptCenter; } //空数据 this.DrawEmptyData=function() { console.log('[ChartPie::DrawEmptyData]') } } /* 中国地图 */ function ChartChinaMap() { this.newMethod=IChartPainting; //派生 this.newMethod(); delete this.newMethod; this.ImageData=null; this.Left; this.Top; this.Width; this.Height; this.ImageWidth; this.ImageHeight; this.DefaultColor=[217,222,239]; this.Color= [ {Name:'海南', Color:'rgb(217,222,223)'}, {Name:'内蒙古', Color:'rgb(217,222,225)'}, {Name:'新疆', Color:'rgb(217,222,226)'}, {Name:'青海', Color:'rgb(217,222,227)'}, {Name:'西藏', Color:'rgb(217,222,228)'}, {Name:'云南', Color:'rgb(217,222,229)'}, {Name:'黑龙江', Color:'rgb(217,222,230)'}, {Name:'吉林', Color:'rgb(217,222,231)'}, {Name:'辽宁', Color:'rgb(217,222,232)'}, {Name:'河北', Color:'rgb(217,222,233)'}, {Name:'山东', Color:'rgb(217,222,234)'}, {Name:'江苏', Color:'rgb(217,222,235)'}, {Name:'浙江', Color:'rgb(217,222,236)'}, {Name:'福建', Color:'rgb(217,222,237)'}, {Name:'广东', Color:'rgb(217,222,238)'}, {Name:'广西', Color:'rgb(217,222,239)'}, {Name:'贵州', Color:'rgb(217,222,240)'}, {Name:'湖南', Color:'rgb(217,222,241)'}, {Name:'江西', Color:'rgb(217,222,242)'}, {Name:'安徽', Color:'rgb(217,222,243)'}, {Name:'湖北', Color:'rgb(217,222,244)'}, {Name:'重庆', Color:'rgb(217,222,245)'}, {Name:'四川', Color:'rgb(217,222,246)'}, {Name:'甘肃', Color:'rgb(217,222,247)'}, {Name:'陕西', Color:'rgb(217,222,248)'}, {Name:'山西', Color:'rgb(217,222,249)'}, {Name:'河南', Color:'rgb(217,222,250)'} ]; this.Draw=function() { let left=this.ChartBorder.GetLeft()+1; let right=this.ChartBorder.GetRight()-1; let top=this.ChartBorder.GetTop()+1; let bottom=this.ChartBorder.GetBottom()-1; let width=this.ChartBorder.GetWidth()-2; let height=this.ChartBorder.GetHeight()-2; let imageWidth=CHINA_MAP_IMAGE.width; let imageHeight=CHINA_MAP_IMAGE.height; let drawImageWidth=imageWidth; let drawImageHeight=imageHeight; if (height0) { for(let i in this.Data) { let item=this.Data[i]; nameMap.set(item.Name,item.Color) } } console.log(this.Data); for(let i in this.Color) { let item=this.Color[i]; if (nameMap.has(item.Name)) { colorMap.set(item.Color,nameMap.get(item.Name)); } else { defaultColorSet.add(item.Color); } } var color; for (let i=0;i0) lineCount=9; //分钟K线多一列时间 if (MARKET_SUFFIX_NAME.IsSHSZStockA(this.HQChart.Symbol) && klineData.FlowCapital>0) ++lineCount; } //this.TitleColor=this.KLineTitlePaint.UnchagneColor; this.IsHScreen=this.ChartFrame.IsHScreen===true; this.Canvas.font=this.Font[0]; this.Width=this.Canvas.measureText(' 擎: 9999.99亿 ').width; this.Height=this.LineHeight*lineCount+2*GetDevicePixelRatio()*2; this.DrawBG(); this.DrawTooltipData(klineData); this.DrawBorder(); } this.DrawTooltipData=function(item) { //console.log('[KLineTooltipPaint::DrawKLineData] ', item); var defaultfloatPrecision=GetfloatPrecision(this.HQChart.Symbol);//价格小数位数 var left=this.GetLeft()+2*GetDevicePixelRatio(); var top=this.GetTop()+3*GetDevicePixelRatio(); if (this.IsHScreen) { this.Canvas.save(); var x=this.GetLeft()+this.Height, y=this.GetTop(); this.Canvas.translate(x, y); this.Canvas.rotate(90 * Math.PI / 180); //x, y 作为原点 left=2*GetDevicePixelRatio(); top=3*GetDevicePixelRatio(); } this.Canvas.textBaseline="top"; this.Canvas.textAlign="left"; this.Canvas.font=this.Font[0]; var labelWidth=this.Canvas.measureText('擎: ').width; var text=IFrameSplitOperator.FormatDateString(item.Date); this.Canvas.fillStyle=this.TitleColor; this.Canvas.fillText(text, left,top); if(item.Time!=null && !isNaN(item.Time) && item.Time>0) { top+=this.LineHeight; text=IFrameSplitOperator.FormatTimeString(item.Time); this.Canvas.fillText(text, left,top); } top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-Open',this.LanguageID); this.Canvas.fillText(text, left,top); var color=this.KLineTitlePaint.GetColor(item.Open,item.YClose); text=item.Open.toFixed(defaultfloatPrecision); this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-High',this.LanguageID); this.Canvas.fillText(text, left,top); var color=this.KLineTitlePaint.GetColor(item.High,item.YClose); var text=item.High.toFixed(defaultfloatPrecision); this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-Low',this.LanguageID); this.Canvas.fillText(text, left,top); var color=this.KLineTitlePaint.GetColor(item.Low,item.YClose); var text=item.Low.toFixed(defaultfloatPrecision); this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-Close',this.LanguageID); this.Canvas.fillText(text, left,top); var color=this.KLineTitlePaint.GetColor(item.Close,item.YClose); var text=item.Close.toFixed(defaultfloatPrecision); this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-Increase',this.LanguageID); this.Canvas.fillText(text, left,top); if (item.YClose>0) { var value=(item.Close-item.YClose)/item.YClose*100; var color = this.KLineTitlePaint.GetColor(value, 0); var text = value.toFixed(2)+'%'; } else { var text='--.--'; var color=this.KLineTitlePaint.GetColor(0, 0); } this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); this.Canvas.fillStyle=this.TitleColor; top+=this.LineHeight; text=g_JSChartLocalization.GetText('Tooltip-Vol',this.LanguageID); this.Canvas.fillText(text, left,top); var text=IFrameSplitOperator.FromatIntegerString(item.Vol,2,this.LanguageID); this.Canvas.fillText(text,left+labelWidth,top); if (IFrameSplitOperator.IsNumber(item.Amount)) { top+=this.LineHeight; text=g_JSChartLocalization.GetText('Tooltip-Amount',this.LanguageID); this.Canvas.fillText(text, left,top); var text=IFrameSplitOperator.FormatValueString(item.Amount,2,this.LanguageID); this.Canvas.fillText(text,left+labelWidth,top); } //换手率 if (MARKET_SUFFIX_NAME.IsSHSZStockA(this.HQChart.Symbol) && item.FlowCapital>0) { top+=this.LineHeight; text=g_JSChartLocalization.GetText('Tooltip-Exchange',this.LanguageID); this.Canvas.fillText(text, left,top); var value=item.Vol/item.FlowCapital*100; var text=value.toFixed(2)+'%'; this.Canvas.fillText(text,left+labelWidth,top); } if (this.IsHScreen) this.Canvas.restore(); } this.DrawBorder=function() { var isHScreen=(this.ChartFrame.IsHScreen===true); var left=this.GetLeft(); var top=this.GetTop(); this.Canvas.strokeStyle=this.BorderColor; if (isHScreen) this.Canvas.strokeRect(ToFixedPoint(left),ToFixedPoint(top),this.Height,this.Width); else this.Canvas.strokeRect(ToFixedPoint(left),ToFixedPoint(top),this.Width,this.Height); } this.DrawBG=function() { var isHScreen=(this.ChartFrame.IsHScreen===true); var left=this.GetLeft(); var top=this.GetTop(); this.Canvas.fillStyle=this.BGColor; if (isHScreen) this.Canvas.fillRect(left,top,this.Height,this.Width); else this.Canvas.fillRect(left,top,this.Width,this.Height); } //设置参数接口 this.SetOption=function(option) { if (option.LineHeight>0) this.LineHeight=option.LineHeight*GetDevicePixelRatio(); if (option.BGColor) this.BGColor=option.BGColor; if (option.LanguageID>0) this.LanguageID=option.LanguageID; } } function MinuteTooltipPaint() { this.newMethod=KLineTooltipPaint; //派生 this.newMethod(); delete this.newMethod; this.ClassName='MinuteTooltipPaint'; this.Left=1*GetDevicePixelRatio(); this.Top=1*GetDevicePixelRatio(); this.YClose; this.GetTop=function() { if (this.IsHScreen) return this.ChartBorder.GetTop(); return this.ChartBorder.GetTop()+this.Top; } this.DrawTooltipData=function(item) { //console.log('[KLineTooltipPaint::DrawKLineData] ', item); var defaultfloatPrecision=GetfloatPrecision(this.HQChart.Symbol);//价格小数位数 var left=this.GetLeft()+2*GetDevicePixelRatio(); var top=this.GetTop()+3*GetDevicePixelRatio(); this.YClose=this.KLineTitlePaint.YClose; if (this.IsHScreen) { this.Canvas.save(); var x=this.GetLeft()+this.Height, y=this.GetTop(); this.Canvas.translate(x, y); this.Canvas.rotate(90 * Math.PI / 180); //x, y 作为原点 left=2*GetDevicePixelRatio(); top=3*GetDevicePixelRatio(); } this.Canvas.textBaseline="top"; this.Canvas.textAlign="left"; this.Canvas.font=this.Font[0]; var labelWidth=this.Canvas.measureText('擎: ').width; var aryDateTime=item.DateTime.split(' '); if (aryDateTime && aryDateTime.length==2) { var text=IFrameSplitOperator.FormatDateString(aryDateTime[0]); this.Canvas.fillStyle=this.TitleColor; this.Canvas.fillText(text, left,top); top+=this.LineHeight; text=IFrameSplitOperator.FormatTimeString(aryDateTime[1]); this.Canvas.fillText(text, left,top); } var close=item.Close; var increase=item.Increase; var vol=item.Vol; var amount=item.Amount; if (item.Before) //读取盘前数据 { close=item.Before.Close; increase=item.Before.Increase; vol=item.Before.Vol; amount=item.Before.Amount; } //最新价格 top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-Price',this.LanguageID); this.Canvas.fillText(text, left,top); var color=this.KLineTitlePaint.GetColor(close,this.YClose); var text=close.toFixed(defaultfloatPrecision); this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); //均价 if (!item.Before) //集合竞价没有均价 { top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-AvPrice',this.LanguageID); this.Canvas.fillText(text, left,top); var color=this.KLineTitlePaint.GetColor(item.AvPrice,this.YClose); var text=item.AvPrice.toFixed(defaultfloatPrecision); this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); } //涨幅 top+=this.LineHeight; this.Canvas.fillStyle=this.TitleColor; text=g_JSChartLocalization.GetText('Tooltip-Increase',this.LanguageID); this.Canvas.fillText(text, left,top); var value=(close-this.YClose)/this.YClose*100; var color = this.KLineTitlePaint.GetColor(value, 0); var text = value.toFixed(2)+'%'; this.Canvas.fillStyle=color; this.Canvas.fillText(text,left+labelWidth,top); //成交量 this.Canvas.fillStyle=this.TitleColor; top+=this.LineHeight; text=g_JSChartLocalization.GetText('Tooltip-Vol',this.LanguageID); this.Canvas.fillText(text, left,top); var text=IFrameSplitOperator.FromatIntegerString(vol,2,this.LanguageID); this.Canvas.fillText(text,left+labelWidth,top); //成交金额 if (IFrameSplitOperator.IsNumber(amount)) { top+=this.LineHeight; text=g_JSChartLocalization.GetText('Tooltip-Amount',this.LanguageID); this.Canvas.fillText(text, left,top); var text=IFrameSplitOperator.FormatValueString(amount,2,this.LanguageID); this.Canvas.fillText(text,left+labelWidth,top); } if (this.IsHScreen) this.Canvas.restore(); } } //股票信息 function StockInfoExtendChartPaint() { this.newMethod=IExtendChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Left=80; this.Right=1; this.Top=1; this.Bottom=1; this.BorderColor=g_JSChartResource.FrameBorderPen; this.Symbol; this.Name; this.TitleFont=["14px 微软雅黑"]; this.Draw=function() { var left=this.ChartBorder.GetRight()+this.Left; var right=this.ChartBorder.GetChartWidth()-this.Right; var y=this.Top+18; var middle=left+(right-left)/2; if (this.Symbol && this.Name) { this.Canvas.font=this.TitleFont[0]; this.Canvas.textAlign="right"; this.Canvas.textBaseline="bottom"; this.Canvas.fillText(this.Symbol,middle-2,y); this.Canvas.textAlign="left"; this.Canvas.fillText(this.Name,middle+2,y); } ; this.Canvas.strokeStyle=this.BorderColor; this.Canvas.moveTo(left,y); this.Canvas.lineTo(right,y); this.Canvas.stroke(); y+=30; this.DrawBorder(); } this.DrawBorder=function() { var left=this.ChartBorder.GetRight()+this.Left; var right=this.ChartBorder.GetChartWidth()-this.Right; var top=this.Top; var bottom=this.ChartBorder.GetChartHeight()-this.Bottom; this.Canvas.strokeStyle=this.BorderColor; this.Canvas.strokeRect(left,top,(right-left),(bottom-top)); } } //筹码分布 function StockChip() { this.newMethod=IExtendChartPainting; //派生 this.newMethod(); delete this.newMethod; this.Name='筹码分布'; this.ClassName='StockChip'; this.HQChart; this.PenBorder=g_JSChartResource.FrameBorderPen; //边框 this.ColorProfit='rgb(255,0,0)'; //盈利的线段 this.ColorNoProfit='rgb(90,141,248)'; //非盈利 this.ColorAveragePrice='rgb(0,139,0)'; //平均价线 this.ColorBG='rgb(190,190,190)'; //筹码背景线段颜色 this.PixelRatio=GetDevicePixelRatio(); this.ShowType=0; //0=所有筹码 1=周期前 2=周期内 this.IsDynamic=true; this.ClientRect={}; this.Font=g_JSChartResource.TitleFont; this.InfoColor='rgb(0,0,0)'; this.DayInfoColor='rgb(255,255,255)'; this.LineHeight=16; this.Left=50*this.PixelRatio; //左边间距 this.IsShowX=false; //是否显示X刻度 成交量 this.ShowXCount=3; this.Width=150*this.PixelRatio; //筹码图宽度 this.ButtonID=Guid(); //工具条Div id this.DAY_COLOR= [ ['rgb(255,0,0)','rgb(255,128,128)','rgb(255,0,128)','rgb(255,100,0)','rgb(192,128,0)','rgb(255,192,0)'], ['rgb(120,80,225)','rgb(160,160,225)','rgb(80,80,255)','rgb(120,120,255)','rgb(32,64,192)','rgb(0,64,128)'], ]; this.SetOption=function(option) { if (!option) return; if (option.ShowType>0) this.ShowType=option.ShowType; if (option.IsShowX) this.IsShowX=option.IsShowX; if (option.ShowXCount>0) this.ShowXCount=option.ShowXCount; if (option.Width>100) this.Width=option.Width*GetDevicePixelRatio(); } this.Draw=function() { this.PixelRatio=GetDevicePixelRatio(); var left=ToFixedPoint(this.ChartBorder.GetRight()+this.Left); var top=ToFixedPoint(this.ChartBorder.GetTop()); var right=ToFixedPoint(left+this.Width-1*this.PixelRatio); var bottom=ToFixedPoint(this.ChartBorder.GetBottom()); var width=right-left; var height=bottom-top; this.ClientRect={Left:left,Top:top,Width:width,Height:height}; if (this.CalculateChip()) { this.DrawFrame(); this.DrawAllChip(); if (this.ShowType==1|| this.ShowType==2) this.DrawDayChip(); this.CalculateCast(); //计算成本 this.DrawChipInfo(); } else { console.log('[StockChip::Draw] no data'); } this.DrawBorder(); if (this.SizeChange==true) this.DrawButton(); this.SizeChange=false; } this.DrawChipInfo=function() { var bottom=this.ClientRect.Top+this.ClientRect.Height-1; var left=this.ClientRect.Left+2; var right=this.ClientRect.Left+this.ClientRect.Width; this.Canvas.font=this.Font; this.Canvas.fillStyle=this.InfoColor; this.Canvas.textBaseline='bottom'; this.Canvas.textAlign='left'; var lineHeight=this.LineHeight*GetDevicePixelRatio(); var text='70%成本价'+ this.Data.Cast[1].MinPrice.toFixed(2)+'-'+this.Data.Cast[1].MaxPrice.toFixed(2)+'集中'+this.Data.Cast[1].Rate.toFixed(2)+'%'; this.Canvas.fillText(text,left,bottom); bottom-=lineHeight; text='90%成本价'+ this.Data.Cast[0].MinPrice.toFixed(2)+'-'+this.Data.Cast[0].MaxPrice.toFixed(2)+'集中'+this.Data.Cast[0].Rate.toFixed(2)+'%';; this.Canvas.fillText(text,left,bottom); bottom-=lineHeight; text='平均成本:'+this.Data.ChipInfo.AveragePrice.toFixed(2)+'元'; this.Canvas.fillText(text,left,bottom); bottom-=lineHeight; text=+this.Data.YPrice.toFixed(2)+'处获利盘:'+this.Data.ChipInfo.YProfitRate.toFixed(2)+'%'; this.Canvas.fillText(text,left,bottom); bottom-=lineHeight; text='获利比例:'; this.Canvas.fillText(text,left,bottom); var textWidth=this.Canvas.measureText(text).width+2; var barLeft=left+textWidth; var barWidth=(right-5-barLeft); this.Canvas.strokeStyle=this.ColorNoProfit; this.Canvas.strokeRect(barLeft,bottom-lineHeight,barWidth,lineHeight); this.Canvas.strokeStyle=this.ColorProfit; this.Canvas.strokeRect(barLeft,bottom-lineHeight,barWidth*(this.Data.ChipInfo.ProfitRate/100),lineHeight); text=this.Data.ChipInfo.ProfitRate.toFixed(2)+'%'; this.Canvas.textAlign='center'; this.Canvas.fillText(text,barLeft+barWidth/2,bottom); bottom-=lineHeight; this.Canvas.textAlign='left'; text='成本分布,日期:'+IFrameSplitOperator.FormatDateString(this.Data.SelectData.Date); if (this.Data.SelectData.Time) text+=' '+IFrameSplitOperator.FormatTimeString(this.Data.SelectData.Time); this.Canvas.fillText(text,left,bottom); bottom-=lineHeight; if (this.ShowType!=1 && this.ShowType!=2) return; var right=this.ClientRect.Left+this.ClientRect.Width-1; this.Canvas.textAlign='right'; var textWidth=50; this.Data.DayChip.sort(function(a,b){return b.Day-a.Day;}) for(var i in this.Data.DayChip) { var item=this.Data.DayChip[i]; var rate=0; if (this.Data.ChipInfo && this.Data.ChipInfo.Vol>0) rate=item.Vol/this.Data.ChipInfo.Vol*100; text=item.Day+'周期'+(this.ShowType==1?'前':'内')+'成本'+rate.toFixed(2)+'%'; if (i==0) textWidth=this.Canvas.measureText(text).width+8; this.Canvas.fillStyle=item.Color; this.Canvas.fillRect(right-textWidth,bottom-lineHeight,textWidth,lineHeight); this.Canvas.fillStyle=this.DayInfoColor; this.Canvas.fillText(text,right,bottom); bottom-=lineHeight; } } this.DrawDayChip=function() { var KLineFrame=this.HQChart.Frame.SubFrame[0].Frame; for(var i in this.Data.DayChip) { var aryPoint=[]; var chipData=this.Data.DayChip[i].Chip; if (!chipData) continue; var totalVol=0; for(var j=0;j0) spanHtml+='  '; spanHtml+=spanItem; } divButton.style.right = Math.floor((chartRight-right+2)/pixelTatio) + "px"; divButton.style.top = top + "px"; //divButton.style.width=toolbarWidth+"px"; divButton.style.height=toolbarHeight+'px'; divButton.innerHTML=spanHtml; var self = this; for(var i in ICON_LIST) { var item=ICON_LIST[i]; $("#"+this.ButtonID+" ."+item.ID).click( { IconID:item.ID, ShowType:i }, function (event) { var id=event.data.IconID; var showType=event.data.ShowType; self.ShowType=showType; if (self.HQChart) self.HQChart.Draw(); for(var i in ICON_LIST) { var item=ICON_LIST[i]; var style=$("#"+self.ButtonID+" ."+item.ID)[0].style; style['color']=item.Color[i==showType?1:0]; } } ) } } this.DrawAllChip=function() { var KLineFrame=this.HQChart.Frame.SubFrame[0].Frame; var selectPrice=this.Data.SelectData.Close; var aryProfitPoint=[]; var aryNoProfitPoint=[]; var totalVol=0,totalAmount=0,totalProfitVol=0, totalYProfitVol=0; //总的成交量, 总的成交金额, 总的盈利的成交量 var yPrice=this.Data.YPrice; var maxPrice=KLineFrame.HorizontalMax; var minPrice=KLineFrame.HorizontalMin; var MaxVol=1; for(var i=0;i=minPrice) { if (MaxVolmaxPrice || price0?totalProfitVol/totalVol*100:0, YProfitRate:totalVol>0?totalYProfitVol/totalVol*100:0 }; if (this.ShowType==0) { this.DrawLines(aryProfitPoint,this.ColorProfit); this.DrawLines(aryNoProfitPoint,this.ColorNoProfit); var averagePrice=this.Data.ChipInfo.AveragePrice; if (averagePrice>0 && averagePrice<=maxPrice && averagePrice>=minPrice) { averagePrice=averagePrice.toFixed(2); this.DrawAveragePriceLine(aryProfitPoint,aryNoProfitPoint,KLineFrame.GetYFromData(averagePrice),this.ColorAveragePrice); } } else //在火焰山模式下, 筹码用一个颜色 { this.DrawLines(aryProfitPoint,this.ColorBG); this.DrawLines(aryNoProfitPoint,this.ColorBG); } } this.CalculateCast=function() //计算 90% 70%的成本价 { if (!this.Data.ChipInfo || !this.Data.ChipInfo.Vol) return; var aryCast= [ {Start:0.05,End:0.95, MaxPrice:0, MinPrice:0, Rate:0}, {Start:0.15,End:0.85, MaxPrice:0, MinPrice:0, Rate:0} ]; var averagePrice=this.Data.ChipInfo.AveragePrice; var totalProfitVol=this.Data.ChipInfo.ProfitVol; var tempVol=0; for(var i=0, castCount=0;iitemCast.Start) { itemCast.MinPrice=price; ++castCount; } if (itemCast.MaxPrice<=0 && rate>itemCast.End) { itemCast.MaxPrice=price; ++castCount; } } } for(var i in aryCast) { var item=aryCast[i]; var addPrice=item.MaxPrice+item.MinPrice; if (addPrice) item.Rate=Math.abs(item.MaxPrice-item.MinPrice)/addPrice*100; } this.Data.Cast=aryCast; } this.DrawArea=function(aryPoint,color) { if (aryPoint.length<=0) return; this.Canvas.fillStyle=color; this.Canvas.beginPath(); this.Canvas.moveTo(this.ClientRect.Left,aryPoint[0].Y); for(var i in aryPoint) { var item=aryPoint[i]; this.Canvas.lineTo(item.X,item.Y); } this.Canvas.lineTo(this.ClientRect.Left,aryPoint[aryPoint.length-1].Y); this.Canvas.fill(); } this.DrawLines=function(aryPoint,color) { if (aryPoint.length<=0) return; this.Canvas.strokeStyle=color; this.Canvas.beginPath(); for(var i in aryPoint) { var item=aryPoint[i]; this.Canvas.moveTo(this.ClientRect.Left,item.Y); this.Canvas.lineTo(item.X,item.Y); } this.Canvas.stroke(); } this.DrawAveragePriceLine=function(aryProfitPoint,aryNoProfitPoint,y,color) { for(var i in aryProfitPoint) { var item=aryProfitPoint[i]; if (item.Y==y) { this.Canvas.strokeStyle=color; this.Canvas.beginPath(); this.Canvas.moveTo(this.ClientRect.Left,item.Y); this.Canvas.lineTo(item.X,item.Y); this.Canvas.stroke(); return; } } for(var i in aryNoProfitPoint) { var item=aryNoProfitPoint[i]; if (item.Y==y) { this.Canvas.strokeStyle=color; this.Canvas.beginPath(); this.Canvas.moveTo(this.ClientRect.Left,item.Y); this.Canvas.lineTo(item.X,item.Y); this.Canvas.stroke(); return; } } } this.DrawBorder=function() { this.Canvas.strokeStyle=this.PenBorder; this.Canvas.strokeRect(this.ClientRect.Left,this.ClientRect.Top,this.ClientRect.Width,this.ClientRect.Height); } this.CalculateChip=function() //计算筹码 { if (!this.HQChart) return false; if (!this.HQChart.FlowCapitalReady) return false; var symbol=this.HQChart.Symbol; if (!symbol) return false; if (MARKET_SUFFIX_NAME.IsSHSZIndex(symbol)) return false; //指数暂时不支持移动筹码 var bindData=this.HQChart.ChartPaint[0].Data; //if (bindData.Period>=4) return false; //分钟K线不支持, 没时间做,以后再做吧 var count=bindData.DataOffset+parseInt(this.HQChart.CursorIndex); if (count>=bindData.Data.length) count=bindData.Data.length-1; var selData=bindData.Data[count]; var yPrice=selData.Close; var mouseY=this.HQChart.LastPoint.Y; if (mouseY) yPrice=this.HQChart.Frame.SubFrame[0].Frame.GetYData(mouseY); //console.log("[StockChip::CalculateChip]",count,this.HQChart.CursorIndex,selData); const rate=1; var aryVol=[]; var seed=1,vol,maxPrice,minPrice; for(let i=count;i>=0;--i) { var item=bindData.Data[i]; var changeRate=1; //换手率 if (item.FlowCapital>0) changeRate=item.Vol/item.FlowCapital; if (i==count) vol=item.Vol*changeRate; else vol=item.Vol*seed; var dataItem={Vol:vol,High:item.High,Low:item.Low}; aryVol.push(dataItem); seed*=(1-changeRate*rate); if (!maxPrice || maxPriceitem.Low) minPrice=item.Low; } //console.log("[StockChip::CalculateChip]",maxPrice,minPrice); if (!maxPrice || !minPrice) return true; maxPrice=parseInt(maxPrice*100); minPrice=parseInt(minPrice*100); var dataCount=maxPrice-minPrice; var aryChip=new Array() for(let i=0;i<=dataCount;++i) { aryChip.push(0); } var maxVol=1; var dayChip=[]; if (this.ShowType==2) { var dayChip= [ {Day:100, Color:this.DAY_COLOR[1][5]}, {Day:60, Color:this.DAY_COLOR[1][4]}, {Day:30, Color:this.DAY_COLOR[1][3]}, {Day:20, Color:this.DAY_COLOR[1][2]}, {Day:10, Color:this.DAY_COLOR[1][1]}, {Day:5, Color:this.DAY_COLOR[1][0]} ]; for(let i in aryVol) { var item=aryVol[i]; var high=parseInt(item.High*100); var low=parseInt(item.Low*100); var averageVol=item.Vol; if (high-low>0) averageVol=item.Vol/(high-low); if (averageVol<=0.000000001) continue; for(var k=0;k=0;--i) { var item=aryVol[i]; var high=parseInt(item.High*100); var low=parseInt(item.Low*100); var averageVol=item.Vol; if (high-low>0) averageVol=item.Vol/(high-low); if (averageVol<=0.000000001) continue; for(var k=0;k0) averageVol=item.Vol/(high-low); if (averageVol<=0.000000001) continue; for(var j=low;j<=high && j<=maxPrice;++j) { var index=j-minPrice; aryChip[index]+=averageVol; if (maxVol10) this.Width=option.Width*pixelRatio; } this.Clear=function() { if (this.ToolsDiv) this.ChartBorder.UIElement.parentNode.removeChild(this.ToolsDiv); } this.Draw = function () { if (this.SizeChange == false) return; //工具列表 const TOOL_LIST = [ [ { HTML: { Title: '线段', IClass: 'iconfont icon-draw_line', ID: 'icon-segment' }, Name: '线段' }, { HTML: { Title: '射线', IClass: 'iconfont icon-draw_rays', ID: 'icon-beam' }, Name: '射线' }, { HTML: { Title: '趋势线', IClass: 'iconfont icon-draw_trendline', ID: 'icon-trendline' }, Name: '趋势线' }, { HTML: { Title: '水平线', IClass: 'iconfont icon-draw_hline', ID: 'icon-hline' }, Name: '水平线' }, { HTML: { Title: '平行线', IClass: 'iconfont icon-draw_parallel_lines', ID: 'icon-parallellines' }, Name: '平行线' }, { HTML: { Title: '平行通道', IClass: 'iconfont icon-draw_parallelchannel', ID: 'icon-parallelchannel' }, Name: '平行通道' }, { HTML: { Title: '价格通道线', IClass: 'iconfont icon-draw_pricechannel', ID: 'icon-pricechannel' }, Name: '价格通道线' }, { HTML: { Title: 'M头W底', IClass: 'iconfont icon-draw_wavemw', ID: 'icon-wavemw' }, Name: 'M头W底' }, ], [ { HTML: { Title: '圆弧', IClass: 'iconfont icon-draw_arc', ID: 'icon-arc' }, Name: '圆弧线' }, { HTML: { Title: '矩形', IClass: 'iconfont icon-rectangle', ID: 'icon-rect' }, Name: '矩形' }, { HTML: { Title: '平行四边形', IClass: 'iconfont icon-draw_quadrangle', ID: 'icon-quad' }, Name: '平行四边形' }, { HTML: { Title: '三角形', IClass: 'iconfont icon-draw_triangle', ID: 'icon-triangle' }, Name: '三角形' }, { HTML: { Title: '圆', IClass: 'iconfont icon-draw_circle', ID: 'icon-circle' }, Name: '圆' }, { HTML: { Title: '对称角度', IClass: 'iconfont icon-draw_symangle', ID: 'icon-symangle' }, Name: '对称角度' }, ], [ { HTML: { Title: '文本', IClass: 'iconfont icon-draw_text', ID: 'icon-text' }, Name: '文本' }, { HTML: { Title: '向上箭头', IClass: 'iconfont icon-arrow_up', ID: 'icon-arrowup' }, Name: 'icon-arrow_up' }, { HTML: { Title: '向下箭头', IClass: 'iconfont icon-arrow_down', ID: 'icon-arrowdown' }, Name: 'icon-arrow_down' }, { HTML: { Title: '向左箭头', IClass: 'iconfont icon-arrow_left', ID: 'icon-arrowleft' }, Name: 'icon-arrow_left' }, { HTML: { Title: '向右箭头', IClass: 'iconfont icon-arrow_right', ID: 'icon-arrowright' }, Name: 'icon-arrow_right' }, ], [ { HTML: { Title: '江恩角度线', IClass: 'iconfont icon-draw_gannfan', ID: 'icon-gannfan' }, Name: '江恩角度线' }, { HTML: { Title: '斐波那契周期线', IClass: 'iconfont icon-draw_fibonacci', ID: 'icon-fibonacci' }, Name: '斐波那契周期线' }, { HTML: { Title: '阻速线', IClass: 'iconfont icon-draw_resline', ID: 'icon-resline' }, Name: '阻速线' }, { HTML: { Title: '黄金分割', IClass: 'iconfont icon-draw_goldensection', ID: 'icon-goldensection' }, Name: '黄金分割' }, { HTML: { Title: '百分比线', IClass: 'iconfont icon-draw_percentage', ID: 'icon-percentage' }, Name: '百分比线' }, { HTML: { Title: '波段线', IClass: 'iconfont icon-draw_waveband', ID: 'icon-waveband' }, Name: '波段线' }, ], [{ HTML: { Title: '全部删除', IClass: 'iconfont icon-recycle_bin', ID: 'icon-delete' }, Name: '全部删除' }] ]; var hqChart = this.HQChart; if (!this.ToolsDiv) { var div = document.createElement("div"); div.className = 'drawtools'; div.id = this.ID; var spanList = ""; //一层菜单 var menuTwoList = ""; //二层菜单 var menuOne = new Array(); TOOL_LIST.forEach(function(item,index){ menuOne.push(item[0]); }); for (var i = 0; i < TOOL_LIST.length; i++) { var itemOut = menuOne[i]; var itemIn = TOOL_LIST[i]; var menuTwoStr = ""; var contentArrow = ""; for (var j = 0; j < itemIn.length; j++) { var currentItem = itemIn[j]; var menuTwoName = currentItem.Name; if(menuTwoName.indexOf('up') > -1){ menuTwoName = "向上箭头"; }else if(menuTwoName.indexOf('down') > -1){ menuTwoName = "向下箭头"; }else if(menuTwoName.indexOf('left') > -1){ menuTwoName = "向左箭头"; }else if(menuTwoName.indexOf('right') > -1){ menuTwoName = "向右箭头"; } menuTwoStr += ''; } if (i !== TOOL_LIST.length - 1) { //不是“全部删除”项 menuTwoList = ''; contentArrow = ''; } else { menuTwoList = ""; contentArrow = ""; } var spanNode = '
' + menuTwoList + contentArrow +'
'; spanList += spanNode; } this.ChartBorder.UIElement.parentNode.appendChild(div); div.innerHTML = spanList; this.ToolsDiv = div; for (var i in TOOL_LIST) { var item = TOOL_LIST[i][0]; $('#' + this.ID + " .first-" + item.HTML.ID).hover(function(){ //箭头的旋转过渡 $(".drawtools").find(".contentArrow").hide(); $(this).find(".contentArrow").removeClass("trans").show(); }); $('#' + this.ID + " .first-" + item.HTML.ID+" .contentArrow").click(function(event){ //点击三角展示二级菜单 event.stopPropagation(); $(".drawtools").find(".menuTwo").hide(); $(this).siblings('.menuTwo').show(); }); $('#' + this.ID + " .first-" + item.HTML.ID+" .trans").click(function(){ //点击三角隐藏二级菜单 event.stopPropagation(); $(this).siblings('.menuTwo').hide(); }); if (item.Name == '全部删除') { $('#' + this.ID + " .first-icon-delete").click(function () { $(".drawtools").find(".menuTwo").hide(); $(this).siblings().removeClass('active'); $(this).addClass('active'); hqChart.ClearChartDrawPicture(); $(".subTolls").css("display", "none"); }); } else { $('#' + this.ID + " .first-" + menuOne[i].HTML.ID).click( //一层菜单类名是:“first-”+item.HTML.ID { // DrawName: menuOne[i].Name, //把画法名字传进去 CurrentIndex:i }, function (event) { $(".drawtools").find(".menuTwo").hide(); $(this).siblings().removeClass('active'); $(this).addClass('active'); hqChart.CreateChartDrawPicture(menuOne[event.data.CurrentIndex].Name); } ); for (var j in TOOL_LIST[i]) { var itemTwo = TOOL_LIST[i][j]; let classname = itemTwo.HTML.IClass; //闭包问题 $('#' + this.ID + ' .' + itemTwo.HTML.ID).hover(function(event){ event.stopPropagation(); $(this).closest('.icon-image').find(".contentArrow").addClass("trans"); }); $('#' + this.ID + ' .' + itemTwo.HTML.ID).click(//二层菜单 { DrawName: itemTwo.Name, //把画法名字传进去 CurrentIndex:i, CurrentData:itemTwo }, function (event) { event.stopPropagation(); $(this).closest('.icon-image').find(".contentArrow").hide(); $(this).siblings().removeClass("current"); $(this).addClass("current"); $(this).closest('.icon-image').children('i').eq(0).removeClass().addClass(classname,"active").attr('title',event.data.CurrentData.HTML.Title); menuOne.splice(event.data.CurrentIndex,1,event.data.CurrentData); $(this).parent().hide(); hqChart.CreateChartDrawPicture(event.data.DrawName); } ); } } } } var curID = this.ID; $(document).click(function(event){ if(!($("#"+curID).is(event.target)) && ($("#"+curID).has(event.target).length === 0)){ $("#"+curID+" .menuTwo").hide(); $("#"+curID+" .contentArrow").hide(); } }); var scrollPos = GetScrollPosition(); var pixelRatio=GetDevicePixelRatio(); // var left=this.ChartBorder.GetChartWidth()-this.Right-this.ToolsWidth; var left=ToFixedPoint(this.ChartBorder.GetRight()+this.Left); // var top = this.Top+this.ChartBorder.UIElement.getBoundingClientRect().top+scrollPos.Top; var top = this.ChartBorder.GetTop(); this.ToolsDiv.style.left = left/pixelRatio + "px"; this.ToolsDiv.style.top = top/pixelRatio + "px"; this.ToolsDiv.style.width = (this.Width-5)/pixelRatio + "px"; this.ToolsDiv.style.height = 'auto'; this.ToolsDiv.style.position = "absolute"; this.ToolsDiv.style.display = "block"; // this.ToolsDiv.style.paddingLeft = "10px"; this.SizeChange == true; } } //弹幕数据 { X:X偏移, Y:Y偏移, Text:内容, Color:颜色 } function BarrageList() { this.PlayList=[]; //正在播放队列 this.Cache=[]; //没有播放的弹幕数据 this.MinLineHeight=40*GetDevicePixelRatio(); this.Height; //高度 this.Step=1; //{Canves:画布, Right:右边坐标, Left:左边坐标, Font:默认字体 } this.GetPlayList=function(obj) { var canves=obj.Canves; var right=obj.Right; var left=obj.Left; var width=right-left; var isMoveStep=obj.IsMoveStep; var list=[]; var yOffset=0; for(var i=0;ithis.MinLineHeight) lineHeight=ary.Height; var bAddNewItem=true; //是否需要加入新弹幕 var bRemoveFirst=false; //是否删除第1个数据 for(var j=0;j0) //最后一个数据了 判断是否需要增加弹幕 { bAddNewItem=false; if (!item.TextWidth) { if (item.Font && item.Font.Name) canves.font=item.Font.Name; else canves.font=obj.Font; item.TextWidth=canves.measureText(playItem.Text+'擎擎').width; } if (item.X>=item.TextWidth) bAddNewItem=true; } else if (j==0) { bRemoveFirst=false; if (!item.TextWidth) { if (item.Font && item.Font.Name) canves.font=item.Font.Name; else canves.font=obj.Font; item.TextWidth=canves.measureText(playItem.Text+'擎擎').width; } if (item.X>width+item.TextWidth) bRemoveFirst=true; } item.X+=this.Step; } if(isMoveStep && bAddNewItem && this.Cache.length>0) //最后一个数据了 判断是否需要增加弹幕 { var cacheItem=this.Cache.shift(); var newItem={ X:0, Text:cacheItem.Text, Color:cacheItem.Color , Font:cacheItem.Font, Info:cacheItem.Info }; ary.Data.push(newItem); } if (isMoveStep && bRemoveFirst && ary.Data.length>0) { var removeItem=ary.Data.shift(); this.OnItemPlayEnd(obj.HQChart,removeItem); } yOffset+=lineHeight; } return list; } //根据高度计算播放队列个数 this.CacluatePlayLine=function(height) { this.Height=height; var lineCount=parseInt(height/this.MinLineHeight); if (this.PlayList.lengthlineCount) { var removeCount=this.PlayList.length-lineCount; for(var i=0;i0) this.BarrageList.Step=option.Step; if (option.MinLineHeight) this.Barrage.MinLineHeight=option.MinLineHeight; } } this.DrawHScreen=function() { var height=this.ChartBorder.GetWidth(); var left=this.ChartBorder.GetTop(); var right=this.ChartBorder.GetBottom(); var top=this.ChartBorder.GetRightEx(); var wdith=this.ChartBorder.GetChartWidth(); if (height!=this.BarrageList.Height) this.BarrageList.CacluatePlayLine(height); this.Canvas.textBaseline="middle"; this.Canvas.textAlign="left"; var play=this.BarrageList.GetPlayList({Canves:this.Canvas, Right:right, Left:left, Font:this.Font, IsMoveStep:this.IsMoveStep, HQChart:this.HQChart}); this.IsMoveStep=false; if (!play) return; this.Canvas.save(); this.Canvas.translate(this.ChartBorder.GetChartHeight(), 0); this.Canvas.rotate(90 * Math.PI / 180); for(var i=0;i0) fontHeight=item.Font.Height; var yOffset=item.Y+parseInt((item.Height-fontHeight)/2); this.Canvas.fillText(item.Text, right-item.X,top+yOffset); } this.Canvas.restore(); } this.Draw=function() { if (this.ChartFrame.IsHScreen) { this.DrawHScreen(); return; } var left=this.ChartBorder.GetLeft(); var right=this.ChartBorder.GetRight(); var top=this.ChartBorder.GetTopEx(); var height=this.ChartBorder.GetHeight(); if (height!=this.BarrageList.Height) this.BarrageList.CacluatePlayLine(height); this.Canvas.textBaseline="middle"; this.Canvas.textAlign="left"; var play=this.BarrageList.GetPlayList({Canves:this.Canvas, Right:right, Left:left, Font:this.Font, IsMoveStep:this.IsMoveStep, HQChart:this.HQChart}); this.IsMoveStep=false; if (!play) return; for(var i=0;i0) fontHeight=item.Font.Height; var yOffset=item.Y+parseInt((item.Height-fontHeight)/2); this.Canvas.fillText(item.Text, right-item.X,top+yOffset); } } } ///////////////////////////////////////////////////////////////////////////////////////////////////// //坐标分割 // // //////////////////////////////////////////////////////////////////////////////////////////////////// function IFrameSplitOperator() { this.ChartBorder; //边框信息 this.Frame; //框架信息 this.FrameSplitData; //坐标轴分割方法 this.SplitCount=5; //刻度个数 this.StringFormat=0; //刻度字符串格式 this.IsShowLeftText=true; //显示左边刻度 this.IsShowRightText=true; //显示右边刻度 this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; ////////////////////// // data.Min data.Max data.Interval data.Count // this.IntegerCoordinateSplit=function(data) { var splitItem=this.FrameSplitData.Find(data.Interval); if (!splitItem) return false; if (data.Interval==splitItem.FixInterval) return true; //调整到整数倍数,不能整除的 +1 var fixMax=parseInt((data.Max/(splitItem.FixInterval)+0.5).toFixed(0))*splitItem.FixInterval; var fixMin=parseInt((data.Min/(splitItem.FixInterval)-0.5).toFixed(0))*splitItem.FixInterval; if (data.Min==0) fixMin=0; //最小值是0 不用调整了. if (fixMin<0 && data.Min>0) fixMin=0; //都是正数的, 最小值最小调整为0 var count=0; for(var i=fixMin;(i-fixMax)<0.00000001;i+=splitItem.FixInterval) { ++count; } data.Interval=splitItem.FixInterval; data.Max=fixMax; data.Min=fixMin; data.Count=count; return true; } this.Filter = function (aryInfo,keepZero) { if (this.SplitCount <= 0 || aryInfo.length <= 0 || aryInfo.length < this.SplitCount) return aryInfo; //分割线比预设的多, 过掉一些 var filter = parseInt(aryInfo.length / this.SplitCount); if (filter <= 1) filter = 2; var data = []; for (var i = 0; i < aryInfo.length; i += filter) { if (i + filter >= aryInfo.length && i != aryInfo.length - 1) //最后一个数据放进去 { data.push(aryInfo[aryInfo.length - 1]); } else { data.push(aryInfo[i]); } } if (this.SplitCount == 2 && data.length>2) //之显示第1个和最后一个刻度 { for(var i=1;i= '1' && char <= '9') return false; } return true; } } //字符串格式化 千分位分割 IFrameSplitOperator.FormatValueThousandsString=function(value,floatPrecision) { if (value==null || isNaN(value)) { if (floatPrecision>0) { var nullText='-.'; for(var i=0;i0){ var numFloat = num.split('.')[1]; var numM = num.split('.')[0]; while (numM.length > 3) { result = ',' + numM.slice(-3) + result; numM = numM.slice(0, numM.length - 3); } if (numM) { result = numM + result + '.' + numFloat; } }else{ while (num.length > 3) { result = ',' + num.slice(-3) + result; num = num.slice(0, num.length - 3); } if (num) { result = num + result; } } return result; } //数据输出格式化 floatPrecision=小数位数 IFrameSplitOperator.FormatValueString=function(value, floatPrecision,languageID) { if (value==null || isNaN(value)) { if (floatPrecision>0) { var nullText='-.'; for(var i=0;i-0.00000000001) { return "0"; } var absValue = Math.abs(value); if (languageID===JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID) { if (absValue < 10000) return value.toFixed(floatPrecision); else if (absValue < 1000000) return (value/1000).toFixed(floatPrecision)+"K"; else if (absValue < 1000000000) return (value/1000000).toFixed(floatPrecision)+"M"; else if (absValue < 1000000000000) return (value/1000000000).toFixed(floatPrecision)+"B"; else return (value/1000000000000).toFixed(floatPrecision)+"T"; } else { if (absValue < 10000) return value.toFixed(floatPrecision); else if (absValue < 100000000) return (value/10000).toFixed(floatPrecision)+"万"; else if (absValue < 1000000000000) return (value/100000000).toFixed(floatPrecision)+"亿"; else return (value/1000000000000).toFixed(floatPrecision)+"万亿"; } return ''; } //整形输出格式化 floatPrecision=小数位数 IFrameSplitOperator.FromatIntegerString=function(value, floatPrecision,languageID) { if (value<10000 && IFrameSplitOperator.IsInteger(value)) floatPrecision=0; //<10000的整形 去掉小数位数 return IFrameSplitOperator.FormatValueString(value, floatPrecision,languageID); } IFrameSplitOperator.NumberToString=function(value) { if (value<10) return '0'+value.toString(); return value.toString(); } IFrameSplitOperator.FormatDateString=function(value,format) { var year=parseInt(value/10000); var month=parseInt(value/100)%100; var day=value%100; switch(format) { case 'MM-DD': return IFrameSplitOperator.NumberToString(month) + '-' + IFrameSplitOperator.NumberToString(day); default: return year.toString() + '-' + IFrameSplitOperator.NumberToString(month) + '-' + IFrameSplitOperator.NumberToString(day); } } IFrameSplitOperator.FormatTimeString=function(value) { if (value<10000) { var hour=parseInt(value/100); var minute=value%100; return IFrameSplitOperator.NumberToString(hour)+':'+ IFrameSplitOperator.NumberToString(minute); } else { var hour=parseInt(value/10000); var minute=parseInt((value%10000)/100); var second=value%100; return IFrameSplitOperator.NumberToString(hour)+':'+ IFrameSplitOperator.NumberToString(minute) + ':' + IFrameSplitOperator.NumberToString(second); } } //报告格式化 IFrameSplitOperator.FormatReportDateString=function(value) { var year=parseInt(value/10000); var month=parseInt(value/100)%100; var monthText; switch(month) { case 3: monthText="一季度报"; break; case 6: monthText="半年报"; break; case 9: monthText="三季度报"; break; case 12: monthText="年报"; break; } return year.toString()+ monthText; } IFrameSplitOperator.FormatDateTimeString=function(value,isShowDate) { var aryValue=value.split(' '); if (aryValue.length<2) return ""; var time=parseInt(aryValue[1]); var minute=time%100; var hour=parseInt(time/100); var text=(hour<10? ('0'+hour.toString()):hour.toString()) + ':' + (minute<10?('0'+minute.toString()):minute.toString()); if (isShowDate==true) { var date=parseInt(aryValue[0]); var year=parseInt(date/10000); var month=parseInt(date%10000/100); var day=date%100; text=year.toString() +'-'+ (month<10? ('0'+month.toString()) :month.toString()) +'-'+ (day<10? ('0'+day.toString()):day.toString()) +" " +text; } return text; } //字段颜色格式化 IFrameSplitOperator.FormatValueColor = function (value, value2) { if (value != null && value2 == null) //只传一个值的 就判断value正负 { if (value == 0) return 'PriceNull'; else if (value > 0) return 'PriceUp'; else return 'PriceDown'; } //2个数值对比 返回颜色 if (value == null || value2 == null) return 'PriceNull'; if (value == value2) return 'PriceNull'; else if (value > value2) return 'PriceUp'; else return 'PriceDown'; } IFrameSplitOperator.IsNumber=function(value) { if (value==null) return false; if (isNaN(value)) return false; return true; } //判断是否是正数 IFrameSplitOperator.IsPlusNumber=function(value) { if (value==null) return false; if (isNaN(value)) return false; return value>0; } //是否是整形 IFrameSplitOperator.IsInteger=function(x) { return (typeof x === 'number') && (x % 1 === 0); } //判断字段是否存在 IFrameSplitOperator.IsObjectExist=function(obj) { if (obj===undefined) return false; if (obj==null) return false; return true; } function FrameSplitKLinePriceY() { this.newMethod=IFrameSplitOperator; //派生 this.newMethod(); delete this.newMethod; this.CoordinateType=0; //坐标类型 0=普通坐标 1=百分比坐标 (右边坐标刻度) this.Symbol; this.Data; //K线数据 (计算百分比坐标) this.FrameSplitData2; //坐标轴分割方法(计算百分比刻度) this.FloatPrecision=null; //小数位数 (设置了就使用这个位数,否则使用品种对应的小数位数) this.Period; //周期 this.KLineChart; this.Custom=[]; //[{Type:0}]; 定制刻度 0=显示最后的价格刻度 this.Operator=function() { var splitData={}; splitData.Max=this.Frame.HorizontalMax; splitData.Min=this.Frame.HorizontalMin; splitData.Count=this.SplitCount; splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1); var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 var width=this.Frame.ChartBorder.GetChartWidth(); //画布的宽度 var isPhoneModel=width<450*pixelTatio; var defaultfloatPrecision=GetfloatPrecision(this.Symbol); if (isPhoneModel && MARKET_SUFFIX_NAME.IsSHSZIndex(this.Symbol)) defaultfloatPrecision = 0; //手机端指数不显示小数位数,太长了 if (this.FloatPrecision!=null) defaultfloatPrecision=this.FloatPrecision; console.log(`[FrameSplitKLinePriceY] Max=${splitData.Max} Min=${splitData.Min} Count=${splitData.Count} isPhoneModel=${isPhoneModel} defaultfloatPrecision=${defaultfloatPrecision} `); if (ChartData.IsTickPeriod(this.Period)) { this.SplitTickData(splitData,defaultfloatPrecision); } else { switch(this.CoordinateType) { case 1: this.SplitPercentage(splitData,defaultfloatPrecision); break; default: this.SplitDefault(splitData,defaultfloatPrecision); break; } } this.Frame.HorizontalInfo = this.Filter(this.Frame.HorizontalInfo,false); this.Frame.HorizontalMax=splitData.Max; this.Frame.HorizontalMin=splitData.Min; console.log(`[FrameSplitKLinePriceY] fixed . Max=${splitData.Max} Min=${splitData.Min} Count=${splitData.Count}`); } this.SplitTickData=function(splitData,floatPrecision) { var aryPrice=this.KLineChart.GetAllPrice(); this.Frame.HorizontalInfo=[]; for(var i in aryPrice) { var value=aryPrice[i]; this.Frame.HorizontalInfo[i]= new CoordinateInfo(); this.Frame.HorizontalInfo[i].Value=value; if (this.IsShowLeftText) this.Frame.HorizontalInfo[i].Message[0]=value.toFixed(floatPrecision); if (this.IsShowRightText) this.Frame.HorizontalInfo[i].Message[1]=value.toFixed(floatPrecision); } } this.SplitPercentage=function(splitData,floatPrecision) //百分比坐标 { var firstOpenPrice=this.GetFirstOpenPrice(); splitData.Max=(splitData.Max-firstOpenPrice)/firstOpenPrice; splitData.Min=(splitData.Min-firstOpenPrice)/firstOpenPrice; splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1); this.IntegerCoordinateSplit2(splitData); this.Frame.HorizontalInfo=[]; for(var i=0,value=splitData.Min;ilatestItem.Open) info.LineColor=g_JSChartResource.FrameLatestPrice.UpBarColor; else if (latestItem.Close0) fixMin=0; //都是正数的, 最小值最小调整为0 var count=0; for(var i=fixMin;(i-fixMax)<0.00000001;i+=splitItem.FixInterval) { ++count; } data.Interval=splitItem.FixInterval; data.Max=fixMax; data.Min=fixMin; data.Count=count; return true; } } function FrameSplitY() { this.newMethod=IFrameSplitOperator; //派生 this.newMethod(); delete this.newMethod; this.SplitCount=3; //刻度个数 this.FloatPrecision = 2; //坐标小数位数(默认2) this.FLOATPRECISION_RANGE=[1,0.1,0.01,0.001,0.0001]; this.GetFloatPrecision=function(value,floatPrecision) { if (value>this.FLOATPRECISION_RANGE[0]) return floatPrecision; if (floatPrecision<0) return 2; for(;floatPrecisionthis.FLOATPRECISION_RANGE[floatPrecision]) break; } return floatPrecision; } this.Operator=function() { var splitData={}; splitData.Max=this.Frame.HorizontalMax; splitData.Min=this.Frame.HorizontalMin; if(this.Frame.YSpecificMaxMin) { splitData.Count=this.Frame.YSpecificMaxMin.Count; splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1); } else { splitData.Count=this.SplitCount; splitData.Interval=(splitData.Max-splitData.Min)/(splitData.Count-1); this.IntegerCoordinateSplit(splitData); } this.Frame.HorizontalInfo=[]; if (this.Frame.YSplitScale) //固定坐标 { for(var i in this.Frame.YSplitScale) { var value=this.Frame.YSplitScale[i]; var coordinate=new CoordinateInfo(); coordinate.Value=value; var absValue=Math.abs(value); if (absValue<0.0000000001) { coordinate.Message[1]=0; } else if (absValue 1000) floatPrecision=0; this.Frame.HorizontalInfo[i].Message[1]=IFrameSplitOperator.FormatValueString(value,floatPrecision,this.LanguageID); } else { var absValue=Math.abs(value); if (absValue<0.0000000001) { this.Frame.HorizontalInfo[i].Message[1]=0; } else if (absValue0 && splitData.Min<0)); this.RemoveZero(this.Frame.HorizontalInfo); this.Frame.HorizontalMax=splitData.Max; this.Frame.HorizontalMin=splitData.Min; } } function FrameSplitKLineX() { this.newMethod=IFrameSplitOperator; //派生 this.newMethod(); delete this.newMethod; this.ShowText=true; //是否显示坐标信息 this.Period; //周期 this.Symbol; //股票代码 this.MinTextDistance=50*GetDevicePixelRatio(); this.SplitDateTime=function() //根据时间分割 { this.Frame.VerticalInfo=[]; var itemWidth=this.Frame.DistanceWidth+this.Frame.DataWidth; var xOffset=this.Frame.Data.DataOffset; var xPointCount=this.Frame.XPointCount; var lastYear=null, lastMonth=null; var textDistance=0; for(var i=0, index=xOffset; ithis.MinTextDistance) { var time=IFrameSplitOperator.FormatTimeString(this.Frame.Data.Data[index].Time); infoData={Value:index-xOffset, Text:time}; } if (infoData) { var info= new CoordinateInfo(); info.Value=infoData.Value; if (this.ShowText) info.Message[0]=infoData.Text; this.Frame.VerticalInfo.push(info); textDistance=0; if (i==0) textDistance=-(this.MinTextDistance/2); } } } this.SplitDate=function() //根据日期分割 { this.Frame.VerticalInfo=[]; var xOffset=this.Frame.Data.DataOffset; var xPointCount=this.Frame.XPointCount; var lastYear=null, lastMonth=null; var minDistance=12; for(var i=0, index=xOffset, distance=minDistance;ivalue) min=value; } if (this.AverageData) { for(var i in this.AverageData.Data) { if (this.AverageData.Data[i]==null) continue; if (maxthis.AverageData.Data[i]) min=this.AverageData.Data[i]; } } for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; //if (item.Status!=OVERLAY_STATUS_ID.STATUS_FINISHED_ID) continue; var range=item.GetMaxMin(); if (range.Max && range.Max>max) max=range.Max; if (range.Min && range.Minthis.LimitPrice.Min) min=this.LimitPrice.Min; } return { Max:max, Min:min }; } this.USASplit=function(range) { var max=range.Max; var min=range.Min; if (max==min) { max=max+max*0.1; min=min-min*0.1; } else { var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 var height=this.Frame.ChartBorder.GetHeight(); //画布的高度 var spacePrice=5*pixelTatio*(max-min)/height; max+=spacePrice; min-=spacePrice; } var showCount=this.SplitCount; var distance=(max-min)/(showCount-1); const minDistance=[1, 0.1, 0.01, 0.001, 0.0001]; var defaultfloatPrecision=GetfloatPrecision(this.Symbol); if (distance0) coordinate.TextColor=g_JSChartResource.UpTextColor; else if (per<0) coordinate.TextColor=g_JSChartResource.DownTextColor; if (this.IsShowRightText) coordinate.Message[1]=IFrameSplitOperator.FormatValueString(per,2)+'%'; //百分比 } this.Frame.HorizontalInfo.push(coordinate); } if (this.YClose>min && this.YClose0? xcoordinateData.MiddleCount: parseInt(minuteCount/2); var xcoordinate = xcoordinateData.Data; this.Frame.XPointCount=minuteCount*this.DayCount; this.Frame.MinuteCount=minuteCount; this.Frame.VerticalInfo=[]; if (this.DayCount<=1) { var beforeDataCount=14; if (this.IsBeforeData) //增加盘前的数据个数 { this.Frame.XPointCount=minuteCount+beforeDataCount; this.Frame.MinuteCount=minuteCount+beforeDataCount; } for(var i in xcoordinate) { var info=new CoordinateInfo(); info.Value=xcoordinate[i][0]; if (this.IsBeforeData) info.Value+=beforeDataCount; if (this.ShowText) info.Message[0]=xcoordinate[i][3]; this.Frame.VerticalInfo[i]=info; } } else { for(var i=this.DayData.length-1,j=0;i>=0;--i,++j) { var info=new CoordinateInfo(); info.Value=j*minuteCount+minuteMiddleCount; info.LineType=-1; //线段不画 if (this.ShowText) info.Message[0]=IFrameSplitOperator.FormatDateString(this.DayData[i].Date, this.ShowFormate==0?'YYYY-MM-DD':'MM-DD'); this.Frame.VerticalInfo.push(info); var info=new CoordinateInfo(); info.Value=(j+1)*minuteCount; this.Frame.VerticalInfo.push(info); } } } } function FrameSplitXData() { this.newMethod=IFrameSplitOperator; //派生 this.newMethod(); delete this.newMethod; this.ShowText=true; //是否显示坐标信息 this.Operator=function() { if (this.Frame.Data==null || this.Frame.XData==null) return; this.Frame.VerticalInfo=[]; var xOffset=this.Frame.Data.DataOffset; var xPointCount=this.Frame.XPointCount; for(var i=0, index=xOffset; i= data.Data.length) dataIndex = data.Data.length - 1; if (dataIndex < 0) return null; var klineData = data.Data[dataIndex]; if (!klineData) return null; this.Close=klineData.Close; var yPoint = this.Frame.GetYFromData(this.Close); return yPoint; } this.Draw=function() { if (!this.LastPoint) return; this.Close=null; var x=this.LastPoint.X; var y=this.LastPoint.Y; var isInClient=false; this.Canvas.beginPath(); this.Canvas.rect(this.Frame.ChartBorder.GetLeft(),this.Frame.ChartBorder.GetTop(),this.Frame.ChartBorder.GetWidth(),this.Frame.ChartBorder.GetHeight()); isInClient=this.Canvas.isPointInPath(x,y); this.PointY=null; this.PointY==null; if (!isInClient) return; if (this.Frame.IsHScreen===true) { this.HScreenDraw(); return; } var left=this.Frame.ChartBorder.GetLeft(); var right=this.Frame.ChartBorder.GetRight(); var top=this.Frame.ChartBorder.GetTopTitle(); var bottom=this.Frame.ChartBorder.GetBottom(); var rightWidth=this.Frame.ChartBorder.Right; var chartRight=this.Frame.ChartBorder.GetChartWidth(); if (this.IsOnlyDrawKLine) //手机端 十字只能画在K线上 { x=this.Frame.GetXFromIndex(this.CursorIndex); if (this.IsShowClose) { var yPoint = this.GetCloseYPoint(this.CursorIndex); if (yPoint != null) y=yPoint; } } this.PointY=[[left,y],[right,y]]; this.PointX=[[x,top],[x,bottom]]; //十字线 if (this.IsShowCorss) { this.Canvas.save(); this.Canvas.strokeStyle=this.PenColor; this.Canvas.setLineDash([3,2]); //虚线 //this.Canvas.lineWidth=0.5 this.Canvas.beginPath(); this.Canvas.moveTo(left,ToFixedPoint(y)); this.Canvas.lineTo(right,ToFixedPoint(y)); if (this.Frame.SubFrame.length>0) { for(var i in this.Frame.SubFrame) { var frame=this.Frame.SubFrame[i].Frame; top=frame.ChartBorder.GetTopTitle(); bottom=frame.ChartBorder.GetBottom(); this.Canvas.moveTo(ToFixedPoint(x),top); this.Canvas.lineTo(ToFixedPoint(x),bottom); } } else { this.Canvas.moveTo(ToFixedPoint(x),top); this.Canvas.lineTo(ToFixedPoint(x),bottom); } this.Canvas.stroke(); this.Canvas.restore(); } var xValue=this.Frame.GetXData(x); var yValueExtend={}; var yValue=this.Frame.GetYData(y,yValueExtend); if (this.IsShowClose && this.Close != null) yValue=this.Close; this.StringFormatX.Value=xValue; this.StringFormatY.Value=yValue; this.StringFormatY.FrameID=yValueExtend.FrameID; //Y轴 if ( ((this.ShowTextMode.Left==1 && this.Frame.ChartBorder.Left>=30) || this.ShowTextMode.Left==2 || (this.ShowTextMode.Right==1 && this.Frame.ChartBorder.Right>=30) || this.ShowTextMode.Right==2 ) && this.StringFormatY.Operator() ) { var text=this.StringFormatY.Text; this.Canvas.font=this.Font; var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素 if (this.Frame.ChartBorder.Left>=30 && this.ShowTextMode.Left==1) { this.Canvas.fillStyle=this.TextBGColor; if (left=30 && this.ShowTextMode.Right==1) { var isOverlayIndex=false; //是否有叠加子坐标 var overlayIndexInterval=null; //子坐标间距 if (yValueExtend.FrameID>=0) { var frame=this.Frame.SubFrame[yValueExtend.FrameID]; isOverlayIndex=frame.OverlayIndex.length>0; overlayIndexInterval=frame.Interval; } this.Canvas.fillStyle=this.TextBGColor; if (isOverlayIndex && textWidth>overlayIndexInterval) //大于子坐标宽度 { var drawRight=right+overlayIndexInterval; if (drawRight>chartRight) drawRight=chartRight; this.Canvas.fillRect(drawRight-2-textWidth,y-this.TextHeight/2,textWidth,this.TextHeight); this.Canvas.textAlign="right"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,drawRight-4,y,textWidth); } else if (rightWidth=right) { this.Canvas.fillRect(right-textWidth,bottom+2,textWidth,this.TextHeight); this.Canvas.textAlign="right"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,right-2,yCenter,textWidth); } else { this.Canvas.fillRect(x-textWidth/2,bottom+2,textWidth,this.TextHeight); this.Canvas.textAlign="center"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,x,yCenter,textWidth); } } //子坐标Y轴 if (yValueExtend.FrameID>=0) { var frame=this.Frame.SubFrame[yValueExtend.FrameID]; var overlayLeft=right; this.Canvas.font=this.Font; for(var i in frame.OverlayIndex) { var item=frame.OverlayIndex[i]; if (item.Frame.IsShow===false) continue; overlayLeft+=frame.Interval; if (overlayLeft+30>chartRight) break; var yValue=item.Frame.GetYData(y); for(var i=2;i>=0;--i) { var text=IFrameSplitOperator.FormatValueString(yValue,i); var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素 if (textWidth0) { for(var i in this.Frame.SubFrame) { var frame=this.Frame.SubFrame[i].Frame; this.Canvas.moveTo(frame.ChartBorder.GetLeft(),ToFixedPoint(y)); this.Canvas.lineTo(frame.ChartBorder.GetRightTitle(),ToFixedPoint(y)); } } else { this.Canvas.moveTo(left,ToFixedPoint(y)); this.Canvas.lineTo(right,ToFixedPoint(y)); } this.Canvas.stroke(); this.Canvas.restore(); } var xValue=this.Frame.GetXData(y); var yValueExtend={}; var yValue=this.Frame.GetYData(x,yValueExtend); this.StringFormatX.Value=xValue; this.StringFormatY.Value=yValue; this.StringFormatY.FrameID=yValueExtend.FrameID; if ( ((this.ShowTextMode.Left==1 && this.Frame.ChartBorder.Top>=30) || this.ShowTextMode.Left==2 || (this.ShowTextMode.Right==1 && this.Frame.ChartBorder.Bottom>=30) || this.ShowTextMode.Right==2) && this.StringFormatY.Operator() ) { var text=this.StringFormatY.Text; this.Canvas.font=this.Font; var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素 if (this.Frame.ChartBorder.Top>=30 && this.ShowTextMode.Left==1) { var xText=x; var yText=top; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.fillStyle=this.TextBGColor; if (top>=textWidth) { this.Canvas.fillRect(0,-(this.TextHeight/2),-textWidth,this.TextHeight); this.Canvas.textAlign="right"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,-2,0,textWidth); } else { this.Canvas.fillRect((textWidth-top),-(this.TextHeight/2),-textWidth,this.TextHeight); this.Canvas.textAlign="right"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,(textWidth-top)-2,0,textWidth); } this.Canvas.restore(); } else if (this.ShowTextMode.Left==2) { var xText=x; var yText=top; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.fillStyle=this.TextBGColor; this.Canvas.fillRect(0,-(this.TextHeight/2),textWidth,this.TextHeight); this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,2,0,textWidth); this.Canvas.restore(); } if (this.Frame.ChartBorder.Bottom>=30 && this.ShowTextMode.Right==1) { var xText=x; var yText=bottom; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.fillStyle=this.TextBGColor; if (bottomWidth>textWidth) { this.Canvas.fillRect(0,-(this.TextHeight/2),textWidth,this.TextHeight); this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,2,0,textWidth); } else { this.Canvas.fillRect((bottomWidth-textWidth),-(this.TextHeight/2),textWidth,this.TextHeight); this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,(bottomWidth-textWidth)+2,0,textWidth); } this.Canvas.restore(); } else if (this.ShowTextMode.Right==2) { var xText=x; var yText=bottom; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.fillStyle=this.TextBGColor; this.Canvas.fillRect(0,-(this.TextHeight/2),-textWidth,this.TextHeight); this.Canvas.textAlign="right"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,-2,0,textWidth); this.Canvas.restore(); } } if (this.ShowTextMode.Bottom===1 && this.StringFormatX.Operator()) { var text=this.StringFormatX.Text; this.Canvas.font=this.Font; this.Canvas.fillStyle=this.TextBGColor; var textWidth=this.Canvas.measureText(text).width+4; //前后各空2个像素 if (y-textWidth/2<3) //左边位置不够了, 顶着左边画 { var xText=left; var yText=y; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.fillRect(0,0,textWidth,this.TextHeight); this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,0,this.TextHeight/2,textWidth); this.Canvas.restore(); } else { var xText=left; var yText=y; this.Canvas.save(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.fillRect(-textWidth/2,0,textWidth,this.TextHeight); this.Canvas.textAlign="center"; this.Canvas.textBaseline="middle"; this.Canvas.fillStyle=this.TextColor; this.Canvas.fillText(text,0,this.TextHeight/2,textWidth); this.Canvas.restore(); } } } } //////////////////////////////////////////////////////////////////////////////// // 等待提示 function ChartSplashPaint() { this.Frame; this.Canvas; //画布 this.Font=g_JSChartResource.DefaultTextFont; //字体 this.TextColor=g_JSChartResource.DefaultTextColor; //文本颜色 this.IsEnableSplash=false; this.SplashTitle='数据加载中'; this.Draw=function() { if (!this.IsEnableSplash) return; if (this.Frame.IsHScreen===true) { this.HScreenDraw(); return; } var xCenter = (this.Frame.ChartBorder.GetLeft() + this.Frame.ChartBorder.GetRight()) / 2; var yCenter = (this.Frame.ChartBorder.GetTop() + this.Frame.ChartBorder.GetBottom()) / 2; this.Canvas.textAlign='center'; this.Canvas.textBaseline='middle'; this.Canvas.fillStyle=this.TextColor; this.Canvas.font=this.Font; this.Canvas.fillText(this.SplashTitle,xCenter,yCenter); } this.HScreenDraw=function() //横屏 { var xCenter = (this.Frame.ChartBorder.GetLeft() + this.Frame.ChartBorder.GetRight()) / 2; var yCenter = (this.Frame.ChartBorder.GetTop() + this.Frame.ChartBorder.GetBottom()) / 2; this.Canvas.save(); this.Canvas.translate(xCenter, yCenter); this.Canvas.rotate(90 * Math.PI / 180); //数据和框子旋转180度 this.Canvas.textAlign='center'; this.Canvas.textBaseline='middle'; this.Canvas.fillStyle=this.TextColor; this.Canvas.font=this.Font; this.Canvas.fillText(this.SplashTitle,0,0); this.Canvas.restore(); } } ///////////////////////////////////////////////////////////////////////////////// // function IChangeStringFormat() { this.Data; this.Value; //数据 this.Text; //输出字符串 this.Operator=function() { return false; } } function HQPriceStringFormat() { this.newMethod=IChangeStringFormat; //派生 this.newMethod(); delete this.newMethod; this.Symbol; this.FrameID; this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; this.YClose; //收盘价 this.PercentageText; //百分比 this.Operator=function() { if (!this.Value) return false; this.PercentageText=null; var defaultfloatPrecision=2; //价格小数位数 if (this.FrameID==0) //第1个窗口显示原始价格 { var defaultfloatPrecision=GetfloatPrecision(this.Symbol); this.Text=this.Value.toFixed(defaultfloatPrecision); if (this.YClose>0) this.PercentageText=((this.Value-this.YClose)*100/this.YClose).toFixed(2); //走势图右边坐标显示百分比 } else { this.Text=IFrameSplitOperator.FormatValueString(this.Value,defaultfloatPrecision,this.LanguageID); } return true; } } function HQDateStringFormat() { this.newMethod=IChangeStringFormat; //派生 this.newMethod(); delete this.newMethod; this.Operator=function() { if (!IFrameSplitOperator.IsNumber(this.Value)) return false; if (!this.Data) return false; var index=this.Value; index=parseInt(index.toFixed(0)); if (this.Data.DataOffset+index>=this.Data.Data.length) return false; var currentData = this.Data.Data[this.Data.DataOffset+index]; this.Text=IFrameSplitOperator.FormatDateString(currentData.Date); if (ChartData.IsMinutePeriod(this.Data.Period,true)) // 分钟周期 { var time = IFrameSplitOperator.FormatTimeString(currentData.Time); this.Text = this.Text + " " + time; } else if (ChartData.IsTickPeriod(this.Data.Period)) //分笔 { var time = IFrameSplitOperator.FormatTimeString(currentData.Time); this.Text = this.Text + " " + time; } return true; } } function HQMinuteTimeStringFormat() { this.newMethod=IChangeStringFormat; //派生 this.newMethod(); delete this.newMethod; this.Frame; this.Symbol; this.IsBeforeData=false; //是否显示盘前数据 this.Operator=function() { if (this.Value==null || isNaN(this.Value)) return false; var index=Math.abs(this.Value); index=parseInt(index.toFixed(0)); var showIndex=index; if (this.Frame && this.Frame.MinuteCount) showIndex=index%this.Frame.MinuteCount; var timeStringData=g_MinuteTimeStringData; var timeData=timeStringData.GetTimeData(this.Symbol); if (!timeData) return false; if (this.IsBeforeData) //增加盘前数据时间刻度 { var allTimeData=[915,916,917,918,919,920,921,922,923,924,925,926,927,928,929] for(var i in timeData) { if (timeData[i]==925) continue; allTimeData.push(timeData[i]) } timeData=allTimeData; } if (showIndex<0) showIndex=0; else if (showIndex>timeData.length) showIndex=timeData.length-1; if (this.Frame && index>=this.Frame.XPointCount) showIndex=timeData.length-1; var time=timeData[showIndex]; this.Text=IFrameSplitOperator.FormatTimeString(time); return true; } } //行情tooltip提示信息格式 var WEEK_NAME=["日","一","二","三","四","五","六"]; function HistoryDataStringFormat() { this.newMethod=IChangeStringFormat; //派生 this.newMethod(); delete this.newMethod; this.Symbol; this.UpColor=g_JSChartResource.UpTextColor; this.DownColor=g_JSChartResource.DownTextColor; this.UnchagneColor=g_JSChartResource.UnchagneTextColor; this.VolColor=g_JSChartResource.DefaultTextColor; this.AmountColor=g_JSChartResource.DefaultTextColor; this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; this.LineCount=0; //一共几行 this.Operator=function() { var data=this.Value.Data; if (!data) return false; var date=new Date(parseInt(data.Date/10000),(data.Date/100%100-1),data.Date%100); var strDate=IFrameSplitOperator.FormatDateString(data.Date); var title2=g_JSChartLocalization.GetText(WEEK_NAME[date.getDay()],this.LanguageID); if (ChartData.IsMinutePeriod(this.Value.ChartPaint.Data.Period,true)) // 分钟周期 { var hour=parseInt(data.Time/100); var minute=data.Time%100; var strHour=hour>=10?hour.toString():"0"+hour.toString(); var strMinute=minute>=10?minute.toString():"0"+minute.toString(); title2 = strHour + ":" + strMinute; } var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数 var increase=null; if (data.YClose>0) increase=(data.Close-data.YClose)/data.YClose*100; var strText= ""+strDate+"  "+title2+""+ ""+g_JSChartLocalization.GetText('DivTooltip-Open',this.LanguageID)+""+ ""+data.Open.toFixed(defaultfloatPrecision)+"
"+ ""+g_JSChartLocalization.GetText('DivTooltip-High',this.LanguageID)+""+ ""+data.High.toFixed(defaultfloatPrecision)+"
"+ ""+g_JSChartLocalization.GetText('DivTooltip-Low',this.LanguageID)+""+ ""+data.Low.toFixed(defaultfloatPrecision)+"
"+ ""+g_JSChartLocalization.GetText('DivTooltip-Close',this.LanguageID)+""+ ""+data.Close.toFixed(defaultfloatPrecision)+"
"+ //" 前收: "+IFrameSplitOperator.FormatValueString(data.YClose,2)+"
"+ ""+g_JSChartLocalization.GetText('DivTooltip-Vol',this.LanguageID)+""+ ""+IFrameSplitOperator.FormatValueString(data.Vol,2,this.LanguageID)+"
"+ ""+g_JSChartLocalization.GetText('DivTooltip-Amount',this.LanguageID)+""+ ""+IFrameSplitOperator.FormatValueString(data.Amount,2,this.LanguageID)+"
"+ ""+g_JSChartLocalization.GetText('DivTooltip-Increase',this.LanguageID)+""+ (increase==null? ""+'--'+"
" : ""+increase.toFixed(2)+'%'+"
"); this.LineCount=8; if(MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol) && data.FlowCapital>0) //换手率 { var value=data.Vol/data.FlowCapital*100; strText+= ""+g_JSChartLocalization.GetText('DivTooltip-Exchange',this.LanguageID)+""+ ""+value.toFixed(2)+'%'+"
"; ++this.LineCount; } //叠加股票 if (this.Value.ChartPaint.Name=="Overlay-KLine") { var title=""+this.Value.ChartPaint.Title+""; strText=title+strText; ++this.LineCount; } this.Text=strText; return true; } this.GetColor=function(price,yclse) { if(price>yclse) return this.UpColor; else if (price"; if(infoList.length > 8) { var strBox="
共"+infoList.length+"条
"; html+=strBox; } this.Text=html; return true; } this.DefaultFormat=function(item) { var strDate=IFrameSplitOperator.FormatDateString(item.Date); var strText=""+strDate+"   "+item.Title+""; return strText; } //大宗交易 this.BlockTradingFormat=function(item) { var showPriceInfo = item.ExtendData; var strDate=IFrameSplitOperator.FormatDateString(item.Date); var strText=""+strDate+"  成交价: "+showPriceInfo.Price.toFixed(2)+"收盘价: "+showPriceInfo.ClosePrice.toFixed(2)+ "
溢折价率: "+ showPriceInfo.Premium.toFixed(2)+"%成交量(万股): "+showPriceInfo.Vol.toFixed(2)+"
"; return strText; } //龙虎榜 this.TradeDetailFormat=function(item) { /*var detail= [ "日价格涨幅偏离值达到9.89%", "日价格涨幅偏离值达格涨幅偏离值达格涨幅偏离值达到9.89%" ] */ var detail=item.ExtendData.Detail; //格式:日期 上榜原因: detail[0].TypeExplain // detail[1].TypeExplain // 一周后涨幅: xx 四周后涨幅: xx var strDate=IFrameSplitOperator.FormatDateString(item.Date); var reasons = []; for(var i in detail) { reasons += ""+detail[i].TypeExplain+"
" // reasons += detail[i] + "
" } var strText= ""+strDate+"   上榜原因:  "+reasons+"
一周后涨幅: "+ item.ExtendData.FWeek.Week1.toFixed(2)+ "%   四周后涨幅: "+ item.ExtendData.FWeek.Week4.toFixed(2)+"%
"; return strText; } //调研 this.ResearchFormat=function(item) { var levels=item.ExtendData.Level; var recPerson=''; if(levels.length==0) { recPerson = "一般调研" } else { for(var j in levels) { if(levels[j]==0) recPerson+="证券代表   "; else if(levels[j]==1) recPerson+="董秘   "; else if(levels[j]==2) recPerson+="总经理   "; else if(levels[j]==3) recPerson+="董事长   "; } recPerson='接待:   '+recPerson; } var researchType=''; if (item.ExtendData.Type && item.ExtendData.Type!='其他') { researchType='   '+''+item.ExtendData.Type+''; if (levels.length==0) recPerson=''; } var strDate=IFrameSplitOperator.FormatDateString(item.Date); var strText=""+strDate+"   "+researchType+recPerson+""; return strText; } //业绩预测 this.PerformanceForecastFormat=function(item) { var reportDate=item.ExtendData.ReportDate; var year=parseInt(reportDate/10000); //年份 var day=reportDate%10000; //比较 这个去掉年份的日期 var reportType; if(day == 1231){ reportType = "年报" }else if(day == 331){ reportType = "一季度报" }else if(day == 630){ reportType = "半年度报" }else if(day == 930){ reportType = "三季度报" } var weekData=""; if (item.ExtendData.FWeek) { if (item.ExtendData.FWeek.Week1!=null) weekData+="一周后涨幅:"+ item.ExtendData.FWeek.Week1.toFixed(2)+"%"; if (item.ExtendData.FWeek.Week4!=null) weekData+=" 四周后涨幅:"+ item.ExtendData.FWeek.Week4.toFixed(2)+"%"; if (weekData.length>0) weekData="
  "+weekData+""; } var strDate=IFrameSplitOperator.FormatDateString(item.Date); var strText=""+strDate+"  "+year+reportType+item.Title+" "+weekData+""; return strText; } this.GetColor=function(price) { if(price>0) return this.UpColor; else if (price<0) return this.DownColor; else return this.UnchagneColor; } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 标题 // // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function IChartTitlePainting() { this.Frame; this.Data=new Array(); this.Canvas; //画布 this.IsDynamic=false; //是否是动态标题 this.Position=0; //标题显示位置 0 框架里的标题 1 框架上面 this.CursorIndex; //数据索引 this.Font=g_JSChartResource.TitleFont; this.Title; //固定标题(可以为空) this.TitleColor=g_JSChartResource.DefaultTextColor; } var PERIOD_NAME=["日线","周线","月线","年线","1分","5分","15分","30分","60分","季线","分笔", "2小时","4小时","","",""]; var RIGHT_NAME=['不复权','前复权','后复权']; function DynamicKLineTitlePainting() { this.newMethod=IChartTitlePainting; //派生 this.newMethod(); delete this.newMethod; this.IsDynamic=true; this.IsShow=true; //是否显示 this.UpColor=g_JSChartResource.UpTextColor; this.DownColor=g_JSChartResource.DownTextColor; this.UnchagneColor=g_JSChartResource.UnchagneTextColor; this.VolColor=g_JSChartResource.DefaultTextColor; this.AmountColor=g_JSChartResource.DefaultTextColor; this.DateTimeColor=g_JSChartResource.DefaultTextColor; this.NameColor = g_JSChartResource.DefaultTextColor; this.Symbol; this.Name; this.SpaceWidth=2*GetDevicePixelRatio(); //获取设备的分辨率; this.OverlayChartPaint; //叠加画法 this.IsShowName=true; //是否显示股票名称 this.IsShowSettingInfo=true; //是否显示设置信息(周期 复权) this.IsShowDateTime=true; //是否显示日期 this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; this.OnDrawEvent; this.GetCurrentKLineData=function() //获取当天鼠标位置所在的K线数据 { if (this.CursorIndex==null || !this.Data) return null; if (this.Data.length<=0) return null; var index=this.CursorIndex; index=parseInt(index.toFixed(0)); var dataIndex=this.Data.DataOffset+index; if (dataIndex>=this.Data.Data.length) dataIndex=this.Data.Data.length-1; if (dataIndex<0) return null; var item=this.Data.Data[dataIndex]; return item; } this.DrawItem=function(item) { var isHScreen=this.Frame.IsHScreen===true; var left=this.Frame.ChartBorder.GetLeft(); var bottom=this.Frame.ChartBorder.GetTop()-this.Frame.ChartBorder.Top/2; var right=this.Frame.ChartBorder.GetRight(); var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数 if (isHScreen) { if (this.Frame.ChartBorder.Right<5) return; var left=2; var bottom=this.Frame.ChartBorder.Right/2; //上下居中显示 var right=this.Frame.ChartBorder.GetHeight(); var xText=this.Frame.ChartBorder.GetChartWidth(); var yText=this.Frame.ChartBorder.GetTop(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); } else { if (this.Frame.ChartBorder.Top<5*GetDevicePixelRatio()) return; } this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.font=this.Font; var position = { Left: left, Bottom: bottom, IsHScreen: isHScreen }; if (this.IsShowName) { if (!this.DrawText(this.Name,this.UnchagneColor,position)) return; } if (this.IsShowSettingInfo) { this.Canvas.fillStyle=this.NameColor; var periodName=''; if (this.Data.Period>CUSTOM_MINUTE_PERIOD_START && this.Data.Period<=CUSTOM_MINUTE_PERIOD_END) periodName=(this.Data.Period-CUSTOM_MINUTE_PERIOD_START)+g_JSChartLocalization.GetText('自定义分钟',this.LanguageID); else if (this.Data.Period>CUSTOM_DAY_PERIOD_START && this.Data.Period<=CUSTOM_DAY_PERIOD_END) periodName=(this.Data.Period-CUSTOM_DAY_PERIOD_START)+g_JSChartLocalization.GetText('自定义日线',this.LanguageID); else periodName=g_JSChartLocalization.GetText(PERIOD_NAME[this.Data.Period],this.LanguageID); var rightName=g_JSChartLocalization.GetText(RIGHT_NAME[this.Data.Right],this.LanguageID); var text="("+periodName+" "+rightName+")"; var isStock=MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol); //是否是指数 if(item.Time!=null || !isStock) text="("+periodName+")"; //分钟K线 指数 没有复权 if (!this.DrawText(text,this.NameColor,position)) return; } if (this.IsShowDateTime) //是否显示日期 { this.Canvas.fillStyle=this.DateTimeColor; var text=IFrameSplitOperator.FormatDateString(item.Date); if (!this.DrawText(text,this.DateTimeColor,position)) return; } if(item.Time!=null && !isNaN(item.Time) && item.Time>0) { var text=IFrameSplitOperator.FormatTimeString(item.Time); if (!this.DrawText(text,this.UnchagneColor,position)) return; } var color=this.GetColor(item.Open,item.YClose); var text=g_JSChartLocalization.GetText('KTitle-Open',this.LanguageID)+item.Open.toFixed(defaultfloatPrecision); if (!this.DrawText(text,color,position)) return; var color=this.GetColor(item.High,item.YClose); var text=g_JSChartLocalization.GetText('KTitle-High',this.LanguageID)+item.High.toFixed(defaultfloatPrecision); if (!this.DrawText(text,color,position)) return; var color=this.GetColor(item.Low,item.YClose); var text=g_JSChartLocalization.GetText('KTitle-Low',this.LanguageID)+item.Low.toFixed(defaultfloatPrecision); if (!this.DrawText(text,color,position)) return; var color=this.GetColor(item.Close,item.YClose); var text=g_JSChartLocalization.GetText('KTitle-Close',this.LanguageID)+item.Close.toFixed(defaultfloatPrecision); if (!this.DrawText(text,color,position)) return; var value=(item.Close-item.YClose)/item.YClose*100; var color = this.GetColor(value, 0); var text = g_JSChartLocalization.GetText('KTitle-Increase',this.LanguageID) + value.toFixed(2)+'%'; if (!this.DrawText(text,color,position)) return; var text=g_JSChartLocalization.GetText('KTitle-Vol',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(item.Vol,2,this.LanguageID); if (!this.DrawText(text,this.VolColor,position)) return; if (IFrameSplitOperator.IsNumber(item.Amount)) { var text=g_JSChartLocalization.GetText('KTitle-Amount',this.LanguageID)+IFrameSplitOperator.FormatValueString(item.Amount,2,this.LanguageID); if (!this.DrawText(text,this.AmountColor,position)) return; } if (MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol) && item.FlowCapital>0) //A股有换手率 { var value=item.Vol/item.FlowCapital*100; //成交量/流通A股*100 var text=g_JSChartLocalization.GetText('KTitle-Exchange',this.LanguageID)+IFrameSplitOperator.FormatValueString(value,2,this.LanguageID)+'%'; if (!this.DrawText(text,this.AmountColor,position)) return; } //叠加股票的名字 for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (!item.Symbol || !item.Title) continue; var name=item.Title; var clrText=item.Color; var text='['+name+']'; if (!this.DrawText(text,clrText,position)) return; } } this.Draw=function() { if (!this.IsShow) return; if (this.CursorIndex==null || !this.Data || this.Data.length<=0) { this.OnDrawEventCallback(null); return; } this.Canvas.font=this.Font; this.SpaceWidth = this.Canvas.measureText('0').width; var index=this.CursorIndex; index=parseInt(index.toFixed(0)); var dataIndex=this.Data.DataOffset+index; if (dataIndex>=this.Data.Data.length) dataIndex=this.Data.Data.length-1; if (dataIndex<0) { this.OnDrawEventCallback(null); return; } var item=this.Data.Data[dataIndex]; this.OnDrawEventCallback(item); this.Canvas.save(); this.DrawItem(item); this.Canvas.restore(); } this.OnDrawEventCallback=function(drawData) { if (!this.OnDrawEvent || !this.OnDrawEvent.Callback) return; var data={ Draw: drawData, Name:'DynamicKLineTitlePainting'}; this.OnDrawEvent.Callback(this.OnDrawEvent,data,this); } this.GetColor=function(price,yclse) { if(price>yclse) return this.UpColor; else if (price right) return false; this.Canvas.fillText(title, position.Left, position.Bottom, textWidth); position.Left += textWidth + this.SpaceWidth; return true; } } function DynamicMinuteTitlePainting() { this.newMethod=DynamicKLineTitlePainting; //派生 this.newMethod(); delete this.newMethod; this.SpaceWidth=1*GetDevicePixelRatio(); this.YClose; this.IsShowDate=false; //标题是否显示日期 this.IsShowName=true; //标题是否显示股票名字 this.OverlayChartPaint; //叠加画法 this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; this.LastShowData; //保存最后显示的数据 给tooltip用 this.OnDrawEvent; this.GetCurrentKLineData=function() //获取当天鼠标位置所在的K线数据 { if (this.LastShowData) return this.LastShowData; if (this.CursorIndex==null || !this.Data) return null; if (this.Data.length<=0) return null; var index=Math.abs(this.CursorIndex-0.5); index=parseInt(index.toFixed(0)); var dataIndex=this.Data.DataOffset+index; if (dataIndex>=this.Data.Data.length) dataIndex=this.Data.Data.length-1; if (dataIndex<0) return null; var item=this.Data.Data[dataIndex]; return item; } this.DrawItem=function(item) { var isHScreen=this.Frame.IsHScreen===true; var left=this.Frame.ChartBorder.GetLeft(); var bottom=this.Frame.ChartBorder.GetTop()-this.Frame.ChartBorder.Top/2; var right=this.Frame.ChartBorder.GetRight(); var defaultfloatPrecision=GetfloatPrecision(this.Symbol);//价格小数位数 if (isHScreen) { if (this.Frame.ChartBorder.Right<5) return; var left=2; var bottom=this.Frame.ChartBorder.Right/2; //上下居中显示 var right=this.Frame.ChartBorder.GetHeight(); var xText=this.Frame.ChartBorder.GetChartWidth(); var yText=this.Frame.ChartBorder.GetTop(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); } else { if (this.Frame.ChartBorder.Top<5) return; } this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.font=this.Font; var position = { Left: left, Bottom: bottom, IsHScreen: isHScreen }; if(this.IsShowName) { if (!this.DrawText(this.Name,this.UnchagneColor,position)) return; } var text=IFrameSplitOperator.FormatDateTimeString(item.DateTime,this.IsShowDate); if (!this.DrawText(text,this.UnchagneColor,position)) return; var close=item.Close; var increase=item.Increase; var vol=item.Vol; var amount=item.Amount; if (item.Before) //读取盘前数据 { close=item.Before.Close; increase=item.Before.Increase; vol=item.Before.Vol; amount=item.Before.Amount; } if (close) { var color=this.GetColor(close,this.YClose); var text=g_JSChartLocalization.GetText('MTitle-Close',this.LanguageID)+close.toFixed(defaultfloatPrecision); if (!this.DrawText(text,color,position)) return; } if (increase!=null) { var color=this.GetColor(increase,0); var text=g_JSChartLocalization.GetText('MTitle-Increase',this.LanguageID)+increase.toFixed(2)+'%'; if (!this.DrawText(text,color,position)) return; } if (item.AvPrice) { var color=this.GetColor(item.AvPrice,this.YClose); var text=g_JSChartLocalization.GetText('MTitle-AvPrice',this.LanguageID)+item.AvPrice.toFixed(defaultfloatPrecision); if (!this.DrawText(text,color,position)) return; } var text=g_JSChartLocalization.GetText('MTitle-Vol',this.LanguageID)+IFrameSplitOperator.FromatIntegerString(vol,2); if (!this.DrawText(text,this.VolColor,position)) return; if (IFrameSplitOperator.IsNumber(amount)) { var text=g_JSChartLocalization.GetText('MTitle-Amount',this.LanguageID)+IFrameSplitOperator.FormatValueString(amount,2); if (!this.DrawText(text,this.AmountColor,position)) return; } //叠加股票的名字 for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (!item.Symbol || !item.Title) continue; var name=item.Title; var clrText=item.Color; var text='['+name+']'; if (!this.DrawText(text,clrText,position)) return; } } this.Draw=function() { this.LastShowData=null; if (!this.IsShow) return; if (this.CursorIndex==null || !this.Data || !this.Data.Data) return; if (this.Data.Data.length<=0) return; this.Canvas.font=this.Font; this.SpaceWidth = this.Canvas.measureText('0').width; //var index=Math.abs(this.CursorIndex-0.5); var index=this.CursorIndex; index=parseInt(index.toFixed(0)); var dataIndex=index+this.Data.DataOffset; if (dataIndex>=this.Data.Data.length) dataIndex=this.Data.Data.length-1; var item=this.Data.Data[dataIndex]; this.LastShowData=item; this.Canvas.save(); this.DrawItem(item); this.Canvas.restore(); } } //字符串输出格式 var STRING_FORMAT_TYPE = { DEFAULT: 1, //默认 2位小数 单位自动转化 (万 亿) ORIGINAL:2, //原始数据 INTEGER:3, //整形数据输出 如果不是整形使用 DEFAULT THOUSANDS:21, //千分位分割 }; function DynamicTitleData(data,name,color) { this.Data=data; this.Name=name; this.Color=color; //字体颜色 this.DataType; //数据类型 this.StringFormat=STRING_FORMAT_TYPE.DEFAULT; //字符串格式 this.FloatPrecision=2; //小数位数 } function DynamicChartTitlePainting() { this.newMethod=IChartTitlePainting; //派生 this.newMethod(); delete this.newMethod; this.IsDynamic=true; this.Data=new Array(); this.Explain; this.ColorIndex; //五彩K线名字 {Name:'名字'} this.TradeIndex; //专家系统名字{Name:'名字'} this.OverlayIndex=new Map(); //叠加指标 key=Identify value={ Data:数据, Title:标题, Identify:标识} this.LanguageID=JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID; this.FormatValue=function(value,item) { if (item.StringFormat==STRING_FORMAT_TYPE.DEFAULT) return IFrameSplitOperator.FormatValueString(value,item.FloatPrecision,this.LanguageID); else if (item.StringFormat==STRING_FORMAT_TYPE.THOUSANDS) return IFrameSplitOperator.FormatValueThousandsString(value,item.FloatPrecision); else if (item.StringFormat==STRING_FORMAT_TYPE.ORIGINAL) return value.toFixed(item.FloatPrecision).toString(); else if (item.StringFormat==STRING_FORMAT_TYPE.INTEGER) return IFrameSplitOperator.FromatIntegerString(value,item.FloatPrecision,this.LanguageID); } this.FormatMultiReport=function(data,format) { var text=""; for(var i in data) { var item = data[i]; let quarter=item.Quarter; let year=item.Year; let value=item.Value; if (text.length>0) text+=','; text+=year.toString(); switch(quarter) { case 1: text+='一季报 '; break; case 2: text+='半年报 '; break; case 3: text+='三季报 '; break; case 4: text+='年报 '; break; } text+=this.FormatValue(value,format); } return text; } this.Draw=function() { if (this.CursorIndex==null ) return; if (!this.Data) return; if (this.Frame.ChartBorder.TitleHeight<5) return; if (this.Frame.IsHScreen===true) { this.Canvas.save(); this.HScreenDraw(); this.Canvas.restore(); return; } var left=this.Frame.ChartBorder.GetLeft()+1; var bottom=this.Frame.ChartBorder.GetTop()+this.Frame.ChartBorder.TitleHeight/2; //上下居中显示 var right=this.Frame.ChartBorder.GetRight(); this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.font=this.Font; if (this.Title) { this.Canvas.fillStyle=this.TitleColor; var textWidth=this.Canvas.measureText(this.Title).width+2; this.Canvas.fillText(this.Title,left,bottom,textWidth); left+=textWidth; } var lockRect=this.Frame.GetLockRect(); if (lockRect) //指标上锁区域不显示动态标题 { var index=Math.abs(this.CursorIndex-0.5); var x=this.Frame.GetXFromIndex(index.toFixed(0)); if (x>=lockRect.Left) return; } for(var i in this.Data) { var item=this.Data[i]; if (!item || !item.Data || !item.Data.Data || !item.Name) continue; if (item.Data.Data.length<=0) continue; var value=null; var valueText=null; if (item.DataType=="StraightLine") //直线只有1个数据 { value=item.Data.Data[0]; valueText=this.FormatValue(value,item); } else { var index=Math.abs(this.CursorIndex-0.5); index=parseInt(index.toFixed(0)); var dataIndex=item.Data.DataOffset+index; if (dataIndex>=item.Data.Data.length) dataIndex=item.Data.Data.length-1; if (dataIndex<0) continue; //if (item.Data.DataOffset+index>=item.Data.Data.length) continue; value=item.Data.Data[dataIndex]; if (value==null) continue; if (item.DataType=="HistoryData-Vol") { value=value.Vol; valueText=this.FormatValue(value,item); } else if (item.DataType=="MultiReport") { valueText=this.FormatMultiReport(value,item); } else { valueText=this.FormatValue(value,item); } } this.Canvas.fillStyle=item.Color; var text=item.Name+":"+valueText; var textWidth=this.Canvas.measureText(text).width+2; //后空2个像素 this.Canvas.fillText(text,left,bottom,textWidth); left+=textWidth; } if (this.Explain) //说明信息 { this.Canvas.fillStyle=this.TitleColor; var text="说明:"+this.Explain; var textWidth=this.Canvas.measureText(text).width+2; if (left+textWidthright) return; var spaceWidth=5*GetDevicePixelRatio(); var drawLeft=left; for(item of this.OverlayIndex) { left+=spaceWidth; var overlayItem=item[1]; if (overlayItem.Title) { this.Canvas.fillStyle=this.TitleColor; var textWidth=this.Canvas.measureText(overlayItem.Title).width+2; drawLeft=left; left+=textWidth; if (left>right) break; this.Canvas.fillText(overlayItem.Title,drawLeft,bottom,textWidth); } for(var i in overlayItem.Data) { var item=overlayItem.Data[i]; if (!item || !item.Data || !item.Data.Data || !item.Name) continue; if (item.Data.Data.length<=0) continue; var value=null; var valueText=null; if (item.DataType=="StraightLine") //直线只有1个数据 { value=item.Data.Data[0]; valueText=this.FormatValue(value,item); } else { var index=Math.abs(this.CursorIndex-0.5); index=parseInt(index.toFixed(0)); var dataIndex=item.Data.DataOffset+index; if (dataIndex>=item.Data.Data.length) dataIndex=item.Data.Data.length-1; if (dataIndex<0) continue; value=item.Data.Data[dataIndex]; if (value==null) continue; if (item.DataType=="HistoryData-Vol") { value=value.Vol; valueText=this.FormatValue(value,item); } else if (item.DataType=="MultiReport") { valueText=this.FormatMultiReport(value,item); } else { valueText=this.FormatValue(value,item); } } this.Canvas.fillStyle=item.Color; var text=item.Name+":"+valueText; var textWidth=this.Canvas.measureText(text).width+2; //后空2个像素 drawLeft=left; left+=textWidth; if (left>right) break; this.Canvas.fillText(text,drawLeft,bottom,textWidth); } if (left>right) break; } } this.HScreenDraw=function() { var xText=this.Frame.ChartBorder.GetRightTitle(); var yText=this.Frame.ChartBorder.GetTop(); this.Canvas.translate(xText, yText); this.Canvas.rotate(90 * Math.PI / 180); var left=1; var bottom=-this.Frame.ChartBorder.TitleHeight/2; //上下居中显示 var right=this.Frame.ChartBorder.GetHeight(); this.Canvas.textAlign="left"; this.Canvas.textBaseline="middle"; this.Canvas.font=this.Font; if (this.Title) { this.Canvas.fillStyle=this.TitleColor; var textWidth=this.Canvas.measureText(this.Title).width+2; this.Canvas.fillText(this.Title,left,bottom,textWidth); left+=textWidth; } var lockRect=this.Frame.GetLockRect(); if (lockRect) //指标上锁区域不显示动态标题 { var index=Math.abs(this.CursorIndex-0.5); var x=this.Frame.GetXFromIndex(index.toFixed(0)); if (x>=lockRect.Top) return; } for(var i in this.Data) { var item=this.Data[i]; if (!item || !item.Data || !item.Data.Data || !item.Name) continue; if (item.Data.Data.length<=0) continue; var value=null; var valueText=null; if (item.DataType=="StraightLine") //直线只有1个数据 { value=item.Data.Data[0]; valueText=this.FormatValue(value,item); } else { var index=Math.abs(this.CursorIndex-0.5); index=parseInt(index.toFixed(0)); var dataIndex=item.Data.DataOffset+index; if (dataIndex>=item.Data.Data.length) dataIndex=item.Data.Data.length-1; if (dataIndex<0) continue; value=item.Data.Data[dataIndex]; if (value==null) continue; if (item.DataType=="HistoryData-Vol") { value=value.Vol; valueText=this.FormatValue(value,item); } else if (item.DataType=="MultiReport") { valueText=this.FormatMultiReport(value,item); } else { valueText=this.FormatValue(value,item); } } this.Canvas.fillStyle=item.Color; var text=item.Name+":"+valueText; var textWidth=this.Canvas.measureText(text).width+2; //后空2个像素 this.Canvas.fillText(text,left,bottom,textWidth); left+=textWidth; } if (this.Explain) //说明信息 { this.Canvas.fillStyle=this.TitleColor; var text="说明:"+this.Explain; var textWidth=this.Canvas.measureText(text).width+2; if (left+textWidth 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==null) return false; var index=parseInt(this.MovePointIndex); if (index===100) //整体移动 { for(var i in this.Point) { this.Point[i].X+=xStep; this.Point[i].Y+=yStep; } } else if (index===0 || index===1 || index===2 || index===3 || index===4 || index===5) { if (index=showCount) ++invaildX; var pt=new Point(); pt.X=this.Frame.GetXFromIndex(item.XValue-data.DataOffset,false); pt.Y=this.Frame.GetYFromData(item.YValue,false); drawPoint.push(pt); } if (option && option.IsCheckX===true) { if (invaildX==this.Value.length) return null; } } else { drawPoint=this.Point; } return drawPoint; } this.IsYValueInFrame=function(yValue) { if (!this.Frame) return false; if (yValue>this.Frame.HorizontalMax || yValue0) { var b2=bottom-ptStart.Y; var a2=a*b2/b; var pt=new Point(); pt.X=ptStart.X+a2; pt.Y=bottom; result.End=pt; var b2=ptEnd.Y-top; var a2=a*b2/b; var pt2=new Point(); pt2.Y=top; pt2.X=ptEnd.X-a2; result.Start=pt2; } else { var b2=bottom-ptStart.Y; var a2=Math.abs(a)*b2/b; var pt=new Point(); pt.X=ptStart.X-a2;; pt.Y=bottom; result.End=pt; var b2=ptEnd.Y-top; var a2=Math.abs(a)*b2/b; var pt2=new Point(); pt2.Y=top; pt2.X=ptEnd.X+a2; result.Start=pt2; } return result; } //坐标是否在点上 返回在第几个点上 this.IsPointInXYValue=function(x,y) { if (!this.Frame) return -1; var data=this.Frame.Data; if (!data) return -1; if (!this.Value) return -1; for(var i=0;i=0) return value; value=this.IsPointInLine(x,y); if (value>=0) return 100; return -1; } this.DrawLine=function(ptStart,ptEnd,isDottedline) { if (isDottedline) this.Canvas.setLineDash([5,10]); this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ptStart.X,ptStart.Y); this.Canvas.lineTo(ptEnd.X,ptEnd.Y); this.Canvas.stroke(); if (isDottedline) this.Canvas.setLineDash([]); } this.CreateLineData=function(ptStart,ptEnd) { var line={Start:new Point(), End:new Point()}; line.Start.Y=ptStart.Y; line.Start.X=ptStart.X; line.End.Y=ptEnd.Y; line.End.X=ptEnd.X; return line; } //导出成存储格式 this.ExportStorageData=function() { var storageData= { ClassName:this.ClassName, Symbol:this.Symbol, Guid:this.Guid, Period:this.Period,Value:[] , FrameID:this.Frame.Identify, LineColor:this.LineColor, AreaColor:this.AreaColor }; for(var i in this.Value) { var item=this.Value[i]; storageData.Value.push({XValue:item.XValue, YValue:item.YValue}); } if (this.Text) storageData.Text=this.Text; //如果有文本, 也导出 if (this.FontOption) storageData.FontOption=this.FontOption; //字体也导出 return storageData; } } IChartDrawPicture.ColorToRGBA=function(color,opacity) { return "rgba(" + parseInt("0x" + color.slice(1, 3)) + "," + parseInt("0x" + color.slice(3, 5)) + "," + parseInt("0x" + color.slice(5, 7)) + "," + opacity + ")"; } IChartDrawPicture.CreateChartDrawPrictrue=function(obj) //创建画图工具 { const MAP_CREATE=new Map( [ ['ChartDrawPictureLine', { Create:function() { return new ChartDrawPictureLine(); }}], ['ChartDrawPictureHaflLine', { Create:function() { return new ChartDrawPictureHaflLine(); }}], ['ChartDrawPictureHorizontalLine', { Create:function() { return new ChartDrawPictureHorizontalLine(); }}], ['ChartDrawPictureTrendLine', { Create:function() { return new ChartDrawPictureTrendLine(); }}], ['ChartDrawPictureRect', { Create:function() { return new ChartDrawPictureRect(); }}], ['ChartDrawPictureArc', { Create:function() { return new ChartDrawPictureArc(); }}], ['ChartDrawPictureWaveMW', { Create:function() { return new ChartDrawPictureWaveMW(); }}], ['ChartDrawPictureParallelLines', { Create:function() { return new ChartDrawPictureParallelLines(); }}], ['ChartDrawPictureParallelChannel', { Create:function() { return new ChartDrawPictureParallelChannel(); }}], ['ChartDrawPicturePriceChannel', { Create:function() { return new ChartDrawPicturePriceChannel(); }}], ['ChartDrawPictureText', { Create:function() { return new ChartDrawPictureText(); }}], ['ChartDrawPictureGannFan', { Create:function() { return new ChartDrawPictureGannFan(); }}], ['ChartDrawPictureResistanceLine', { Create:function() { return new ChartDrawPictureResistanceLine(); }}], ['ChartDrawPictureGoldenSection', { Create:function() { return new ChartDrawPictureGoldenSection(); }}], ['ChartDrawPicturePercentage', { Create:function() { return new ChartDrawPicturePercentage(); }}], ['ChartDrawPictureWaveBand', { Create:function() { return new ChartDrawPictureWaveBand(); }}], ['ChartDrawPictureTriangle', { Create:function() { return new ChartDrawPictureTriangle(); }}], ['ChartDrawPictureSymmetryAngle', { Create:function() { return new ChartDrawPictureSymmetryAngle(); }}], ['ChartDrawPictureCircle', { Create:function() { return new ChartDrawPictureCircle(); }}], ['ChartDrawPictureQuadrangle', { Create:function() { return new ChartDrawPictureQuadrangle(); }}], ['ChartDrawPictureFibonacci', { Create:function() { return new ChartDrawPictureFibonacci(); }}], ['ChartDrawPictureIconFont', { Create:function() { return new ChartDrawPictureIconFont(); }}] ]); if (!MAP_CREATE.has(obj.ClassName)) return null; var item=MAP_CREATE.get(obj.ClassName); var chartDraw=item.Create(); if (obj.Period>=0) chartDraw.Period=obj.Period; if (obj.Guid) chartDraw.Guid=obj.Guid; if (obj.Symbol) chartDraw.Symbol=obj.Symbol; if (obj.Value) chartDraw.Value=obj.Value; if (obj.Text) chartDraw.Text=obj.Text; if (obj.LineColor) chartDraw.LineColor=obj.LineColor; if (obj.AreaColor) chartDraw.AreaColor=obj.AreaColor; if (obj.FontOption) chartDraw.FontOption=obj.FontOption; return chartDraw; } //画图工具-线段 function ChartDrawPictureLine() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureLine'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint( {IsCheckX:true, IsCheckY:true} ); if (!drawPoint) return; if (drawPoint.length!=2) return; this.ClipFrame(); var ptStart=drawPoint[0]; var ptEnd=drawPoint[1]; this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ptStart.X,ptStart.Y); this.Canvas.lineTo(ptEnd.X,ptEnd.Y); this.Canvas.stroke(); var line={Start:ptStart, End:ptEnd}; this.LinePoint.push(line); this.DrawPoint(drawPoint); //画点 this.Canvas.restore(); } } //画图工具-射线 function ChartDrawPictureHaflLine() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureHaflLine'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint || drawPoint.length!=2) return; var ptStart=drawPoint[0]; var ptEnd=drawPoint[1]; this.ClipFrame(); this.Canvas.strokeStyle=this.LineColor; 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.stroke(); var line={Start:ptStart, End:ptEnd}; this.LinePoint.push(line); this.DrawPoint(drawPoint); //画点 this.Canvas.restore(); } 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; } } } // 画图工具-水平线 function ChartDrawPictureHorizontalLine() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.PointCount=1; this.ClassName='ChartDrawPictureHorizontalLine'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Font=16*GetDevicePixelRatio() +"px 微软雅黑"; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint(); if (!drawPoint || drawPoint.length!=1) return; if (!this.Frame) return; if (this.Value.length!=1) return; if (!this.IsYValueInFrame(this.Value[0].YValue)) return null; var left=this.Frame.ChartBorder.GetLeft(); var right=this.Frame.ChartBorder.GetRight(); this.ClipFrame(); this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(left,drawPoint[0].Y); this.Canvas.lineTo(right,drawPoint[0].Y); this.Canvas.stroke(); var line={Start:new Point(), End:new Point()}; line.Start.X=left; line.Start.Y=drawPoint[0].Y; line.End.X=right; line.End.Y=drawPoint[0].Y; this.LinePoint.push(line); //显示价格 var yValue=this.Frame.GetYData(drawPoint[0].Y); this.Canvas.fillStyle=this.LineColor; this.Canvas.textAlign="let"; this.Canvas.textBaseline="bottom"; this.Canvas.font=this.Font; this.Canvas.fillText(yValue.toFixed(2),left,drawPoint[0].Y); this.DrawPoint(drawPoint); this.Canvas.restore(); } } //趋势线 function ChartDrawPictureTrendLine() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureTrendLine'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint || drawPoint.length!=2) return; var ptStart=drawPoint[0]; var ptEnd=drawPoint[1]; var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd); this.ClipFrame(); this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(extendLine.Start.X,extendLine.Start.Y); this.Canvas.lineTo(extendLine.End.X,extendLine.End.Y); this.Canvas.stroke(); var line={Start:ptStart, End:ptEnd}; this.LinePoint.push(line); this.DrawPoint(drawPoint); //画点 this.Canvas.restore(); } } //画图工具-矩形 function ChartDrawPictureRect() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureRect'; this.Draw=function() { var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint || drawPoint.length!=2) return; this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); this.ClipFrame(); this.Canvas.strokeStyle=this.LineColor; 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.stroke(); //透明背景 this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.fillRect(drawPoint[0].X,drawPoint[0].Y,drawPoint[1].X-drawPoint[0].X,drawPoint[1].Y-drawPoint[0].Y); 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); //console.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.ClassName='ChartDrawPictureArc'; 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); //console.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; } } //M头W底 function ChartDrawPictureWaveMW() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureWaveMW'; this.PointCount=2; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint) return; //var points=drawPoint.slice(0); this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); this.ClipFrame(); this.CalculateLines(drawPoint); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End); } this.DrawPoint(drawPoint); //画点 this.Canvas.restore(); } this.CalculateLines=function(points) { if (!this.Frame) return; if (points.length<2) return; if (this.Status==2) { var line={Start:new Point(), End:new Point()}; line.Start.Y=points[0].Y; line.Start.X=points[0].X; line.End.Y=points[1].Y; line.End.X=points[1].X; this.LinePoint.push(line); var xMove=points[1].X-points[0].X; line={Start:new Point(), End:new Point()}; line.Start.Y=points[1].Y; line.Start.X=points[1].X; line.End.Y=points[0].Y; line.End.X=points[1].X+xMove; this.LinePoint.push(line); var ptStart=line.End; var newPt=new Point(); newPt.X=ptStart.X; newPt.Y=ptStart.Y; this.Point[2]=newPt; line={Start:new Point(), End:new Point()}; line.Start.Y=ptStart.Y; line.Start.X=ptStart.X; line.End.Y=points[1].Y; line.End.X=ptStart.X+xMove; this.LinePoint.push(line); var ptStart=line.End; var newPt=new Point(); newPt.X=ptStart.X; newPt.Y=ptStart.Y; this.Point[3]=newPt; line={Start:new Point(), End:new Point()}; line.Start.Y=ptStart.Y; line.Start.X=ptStart.X; line.End.Y=points[0].Y; line.End.X=ptStart.X+xMove; this.LinePoint.push(line); var ptStart=line.End; var newPt=new Point(); newPt.X=ptStart.X; newPt.Y=ptStart.Y; this.Point[4]=newPt; this.PointCount=this.Point.length; } else if (points.length==5) { var line={Start:new Point(), End:new Point()}; line.Start.Y=points[0].Y; line.Start.X=points[0].X; line.End.Y=points[1].Y; line.End.X=points[1].X; this.LinePoint.push(line); var line={Start:new Point(), End:new Point()}; line.Start.Y=points[1].Y; line.Start.X=points[1].X; line.End.Y=points[2].Y; line.End.X=points[2].X; this.LinePoint.push(line); var line={Start:new Point(), End:new Point()}; line.Start.Y=points[2].Y; line.Start.X=points[2].X; line.End.Y=points[3].Y; line.End.X=points[3].X; this.LinePoint.push(line); var line={Start:new Point(), End:new Point()}; line.Start.Y=points[3].Y; line.Start.X=points[3].X; line.End.Y=points[4].Y; line.End.X=points[4].X; this.LinePoint.push(line); } } } //平行线 function ChartDrawPictureParallelLines() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureParallelLines'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.PointCount=3; this.LastPoint; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint) return; this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); var points=drawPoint.slice(0); this.CalculateLines(points); this.ClipFrame(); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End); } this.DrawArea(); this.DrawPoint(points); //画点 this.Canvas.restore(); } this.SetLastPoint=function(obj) { this.LastPoint={X:obj.X,Y:obj.Y}; } this.DrawArea=function() { if (this.LinePoint.length!=2) return; this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.moveTo(this.LinePoint[0].Start.X,this.LinePoint[0].Start.Y); this.Canvas.lineTo(this.LinePoint[0].End.X,this.LinePoint[0].End.Y); this.Canvas.lineTo(this.LinePoint[1].End.X,this.LinePoint[1].End.Y); this.Canvas.lineTo(this.LinePoint[1].Start.X,this.LinePoint[1].Start.Y); this.Canvas.closePath(); this.Canvas.fill(); } this.CalculateLines=function(points) { if (this.PointStatus==2 && this.LastPoint) { var pt=new Point(); pt.X=this.LastPoint.X; pt.Y=this.LastPoint.Y; points[2]=pt; } if (points.length==2) { var linePoint=this.CalculateExtendLinePoint(points[0],points[1]); this.LinePoint.push(linePoint); } else if (points.length==3) { var linePoint=this.CalculateExtendLinePoint(points[0],points[1]); this.LinePoint.push(linePoint); //计算平行线 var xMove=points[2].X-points[1].X; var yMove=points[2].Y-points[1].Y; var ptStart=new Point(); var ptEnd=new Point(); ptStart.X=points[0].X+xMove; ptStart.Y=points[0].Y+yMove; ptEnd.X=points[1].X+xMove; ptEnd.Y=points[1].Y+yMove; linePoint=this.CalculateExtendLinePoint(ptStart,ptEnd); this.LinePoint.push(linePoint); } } } //价格通道线 function ChartDrawPicturePriceChannel() { this.newMethod=ChartDrawPictureParallelLines; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPicturePriceChannel'; this.CalculateLines=function(points) { if (this.PointStatus==2 && this.LastPoint) { var pt=new Point(); pt.X=this.LastPoint.X; pt.Y=this.LastPoint.Y; points[2]=pt; } if (points.length==2) { var linePoint=this.CalculateExtendLinePoint(points[0],points[1]); this.LinePoint.push(linePoint); } else if (points.length==3) { var linePoint=this.CalculateExtendLinePoint(points[0],points[1]); this.LinePoint.push(linePoint); //计算平行线 var xMove=points[2].X-points[1].X; var yMove=points[2].Y-points[1].Y; var ptStart=new Point(); var ptEnd=new Point(); ptStart.X=points[0].X+xMove; ptStart.Y=points[0].Y+yMove; ptEnd.X=points[1].X+xMove; ptEnd.Y=points[1].Y+yMove; linePoint=this.CalculateExtendLinePoint(ptStart,ptEnd); this.LinePoint.push(linePoint); var ptStart=new Point(); var ptEnd=new Point(); ptStart.X=points[0].X-xMove; ptStart.Y=points[0].Y-yMove; ptEnd.X=points[1].X-xMove; ptEnd.Y=points[1].Y-yMove; linePoint=this.CalculateExtendLinePoint(ptStart,ptEnd); this.LinePoint.push(linePoint); } } this.DrawArea=function() { if (this.LinePoint.length!=3) return; this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.moveTo(this.LinePoint[1].Start.X,this.LinePoint[1].Start.Y); this.Canvas.lineTo(this.LinePoint[1].End.X,this.LinePoint[1].End.Y); this.Canvas.lineTo(this.LinePoint[2].End.X,this.LinePoint[2].End.Y); this.Canvas.lineTo(this.LinePoint[2].Start.X,this.LinePoint[2].Start.Y); this.Canvas.closePath(); this.Canvas.fill(); } } //平行通道 function ChartDrawPictureParallelChannel() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureParallelChannel'; this.ChannelWidth=50; this.AreaColor='rgba(25,25,25,0.4)'; this.LinePoint=[]; //计算需要画的点的坐标 this.CalculateDrawPoint=function() { if (this.Status<2) return null; if(!this.Point.length || !this.Frame) return null; var data=this.Frame.Data; if (!data) return null; var drawPoint=[]; if (this.Status==10) //完成 { for(var i=0; i<2; ++i) { 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 { for(var i=0; i=2) { var linePoint={Start:new Point(), End:new Point() }; linePoint.Start.X=drawPoint[0].X; linePoint.Start.Y=drawPoint[0].Y; linePoint.End.X=drawPoint[1].X; linePoint.End.Y=drawPoint[1].Y; this.LinePoint.push(linePoint); if (drawPoint.length==3 || this.Status==10) { var x=linePoint.End.X-linePoint.Start.X; var y=linePoint.End.Y-linePoint.Start.Y; var angle=Math.atan(Math.abs(x/y)); var yMove=this.ChannelWidth/Math.sin(angle); //console.log('[ChartDrawPictureParallelChannel::CalculateDrawPoint]',xMove); linePoint={Start:new Point(), End:new Point() }; linePoint.Start.X=drawPoint[0].X; linePoint.Start.Y=drawPoint[0].Y-yMove; linePoint.End.X=drawPoint[1].X; linePoint.End.Y=drawPoint[1].Y-yMove; this.LinePoint.push(linePoint); var ptCenter=new Point(); ptCenter.X=linePoint.Start.X+(linePoint.End.X-linePoint.Start.X)/2; ptCenter.Y=linePoint.Start.Y+(linePoint.End.Y-linePoint.Start.Y)/2; drawPoint[3]=ptCenter; this.Point[2]=ptCenter; var xValue=parseInt(this.Frame.GetXData(ptCenter.X))+data.DataOffset; var yValue=this.Frame.GetYData(ptCenter.Y); this.Value[2]={XValue:xValue,YValue:yValue}; this.PointCount=this.Point.length; //完成以后是3个点 } } return drawPoint; } this.DrawLine=function(ptStart,ptEnd) { this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ptStart.X,ptStart.Y); this.Canvas.lineTo(ptEnd.X,ptEnd.Y); this.Canvas.stroke(); } this.DrawArea=function(pt,pt2,pt3,pt4) { this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.moveTo(pt.X,pt.Y); this.Canvas.lineTo(pt2.X,pt2.Y); this.Canvas.lineTo(pt3.X,pt3.Y); this.Canvas.lineTo(pt4.X,pt4.Y); this.Canvas.closePath(); this.Canvas.fill(); } this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint(); if (!drawPoint) return; this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); this.ClipFrame(); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End); } if (this.LinePoint.length==2) { this.DrawArea(this.LinePoint[0].Start,this.LinePoint[0].End,this.LinePoint[1].End,this.LinePoint[1].Start); } this.Canvas.restore(); this.DrawPoint(drawPoint); //画点 } //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) { if (this.MovePointIndex=this.Point.length) continue; pt.X=this.Point[i].X; pt.Y=this.Point[i].Y; } this.Canvas.beginPath(); this.Canvas.arc(pt.X,pt.Y,5,0,360); if (this.Canvas.isPointInPath(x,y)) return i; } //是否在线段上 for(var i in this.LinePoint) { var item=this.LinePoint[i]; var ptStart=item.Start; var ptEnd=item.End; this.Canvas.beginPath(); this.Canvas.moveTo(ptStart.X,ptStart.Y+5); this.Canvas.lineTo(ptStart.X,ptStart.Y-5); this.Canvas.lineTo(ptEnd.X,ptEnd.Y-5); this.Canvas.lineTo(ptEnd.X,ptEnd.Y+5); this.Canvas.closePath(); if (this.Canvas.isPointInPath(x,y)) return 100; } return -1; } } //文本 function ChartDrawPictureText() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureText'; this.Text='文本'; this.PointCount=1; this.FontOption={ Family:'微软雅黑', Size:20, Weight:null, Style:null }; //Weight(bold 粗体), Style(italic) //矢量图片 //this.Text="\ue606"; //this.FontOption={ Family:'iconfont', Size:20, Weight:null, Style:null }; //Weight(bold 粗体), Style(italic) this.TextRect=null; //文字区域 this.IsInitialized=false; //是否初始化了 this.SettingMenu; this.HQChart; this.Draw=function(textFont) { this.TextRect=null; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint || drawPoint.length!=1) return; this.ClipFrame(); this.Canvas.fillStyle=this.LineColor; this.Canvas.textAlign="center"; this.Canvas.textBaseline="bottom"; this.Canvas.font=this.GetTextFont(); this.Canvas.fillText(this.Text,drawPoint[0].X,drawPoint[0].Y); var textWidth=this.Canvas.measureText(this.Text).width; this.TextRect={}; this.TextRect.Left=drawPoint[0].X-textWidth/2; this.TextRect.Top=drawPoint[0].Y-this.FontOption.Size; this.TextRect.Width=textWidth; this.TextRect.Height=this.FontOption.Size; //this.Canvas.strokeRect(this.TextRect.Left,this.TextRect.Top,this.TextRect.Width,this.TextRect.Height); this.Canvas.restore(); if (this.IsInitialized===false) { this.SetTextOption(); this.IsInitialized=true; } } //根据设置动态生成字体 this.GetTextFont=function() { const defaultFont=16*GetDevicePixelRatio() +"px 微软雅黑"; if (!this.FontOption || !this.FontOption.Family || this.FontOption.Size<=0) return defaultFont; var font=''; if (this.FontOption.Color) font+=this.FontOption.Color+' '; if (this.FontOption.Style) font+=this.FontOption.Style+' '; if (this.FontOption.Weight) font+=this.FontOption.Weight+' '; if (this.FontOption.Size>=0) font+=this.FontOption.Size*GetDevicePixelRatio()+'px '; font+=this.FontOption.Family; return font; } this.SetTextOption=function() { console.log('[ChartDrawPictureText::SetTextOption]'); //创建div设置窗口 if (!this.SettingMenu) this.SettingMenu=new ChartPictureTextSettingMenu(this.Frame.ChartBorder.UIElement.parentNode); this.SettingMenu.ChartPicture=this; this.SettingMenu.HQChart=this.HQChart; this.SettingMenu.Position={Left:this.TextRect.Left+this.TextRect.Width,Top:this.TextRect.Top}; this.SettingMenu.DoModal(); } this.IsPointIn=function(x,y) { if (!this.Frame || this.Status!=10) return -1; var data=this.Frame.Data; if (!data) return -1; if (!this.TextRect) return -1; this.Canvas.beginPath(); this.Canvas.rect(this.TextRect.Left,this.TextRect.Top,this.TextRect.Width,this.TextRect.Height); if (this.Canvas.isPointInPath(x,y)) return 100; return -1; } } //iconfont 图片 function ChartDrawPictureIconFont() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureIconFont'; this.PointCount=1; //矢量图片 this.Text="\ue606"; this.FontOption={ Family:'iconfont', Size:24}; //Weight(bold 粗体), Style(italic) this.TextRect=null; //文字区域 this.SettingMenu; this.Draw=function() { this.TextRect=null; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint || drawPoint.length!=1) return; var font=this.GetTextFont(); if (!font) return; this.ClipFrame(); this.Canvas.fillStyle=this.LineColor; this.Canvas.textAlign="center"; this.Canvas.textBaseline="bottom"; this.Canvas.font=font; this.Canvas.fillText(this.Text,drawPoint[0].X,drawPoint[0].Y); var textWidth=this.Canvas.measureText(this.Text).width; this.TextRect={}; this.TextRect.Left=drawPoint[0].X-textWidth/2; this.TextRect.Top=drawPoint[0].Y-this.FontOption.Size; this.TextRect.Width=textWidth; this.TextRect.Height=this.FontOption.Size; //this.Canvas.strokeRect(this.TextRect.Left,this.TextRect.Top,this.TextRect.Width,this.TextRect.Height); this.Canvas.restore(); } //根据设置动态生成字体 this.GetTextFont=function() { if (!this.FontOption || !this.FontOption.Family || this.FontOption.Size<=0) return null; var font=''; if (this.FontOption.Size>=0) font+=this.FontOption.Size*GetDevicePixelRatio()+'px '; font+=this.FontOption.Family; return font; } this.IsPointIn=function(x,y) { if (!this.Frame || this.Status!=10) return -1; var data=this.Frame.Data; if (!data) return -1; if (!this.TextRect) return -1; this.Canvas.beginPath(); this.Canvas.rect(this.TextRect.Left,this.TextRect.Top,this.TextRect.Width,this.TextRect.Height); if (this.Canvas.isPointInPath(x,y)) return 100; return -1; } } //江恩角度线(Gann Fan),亦又称作甘氏线的 function ChartDrawPictureGannFan() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureGannFan'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.LinePoint=[]; this.Font=16*GetDevicePixelRatio() +"px 微软雅黑"; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint) return; if (drawPoint.length!=2) return; this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); this.ClipFrame(); var quadrant=this.GetQuadrant(drawPoint[0],drawPoint[1]); if (quadrant===1 || quadrant===4) { this.CalculateLines(drawPoint[0],drawPoint[1],quadrant); this.DrawArea(); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End,item.IsDottedLine); } for(var i in this.LinePoint) { var item =this.LinePoint[i]; if (item.Text && item.PtEnd) this.DrawTitle(item.PtEnd,item.Text); } } else { this.DrawLine(drawPoint[0],drawPoint[1],false); } this.Canvas.restore(); this.DrawPoint(drawPoint); //画点 } //获取在第几象限 this.GetQuadrant=function(ptStart,ptEnd) { if (ptStart.XptEnd.Y) return 1; else if (ptStart.XptEnd.Y) return 2; else if (ptStart.X < ptEnd.X && ptStart.Y< ptEnd.Y) return 4; else return 3; } //isDotline 是否是虚线 this.DrawLine=function(ptStart,ptEnd,isDottedline) { if (isDottedline) this.Canvas.setLineDash([5,10]); this.Canvas.strokeStyle=this.LineColor; this.Canvas.beginPath(); this.Canvas.moveTo(ptStart.X,ptStart.Y); this.Canvas.lineTo(ptEnd.X,ptEnd.Y); this.Canvas.stroke(); if (isDottedline) this.Canvas.setLineDash([]); } this.DrawTitle=function(pt,text) { this.Canvas.fillStyle=this.LineColor; this.Canvas.textAlign="left"; this.Canvas.textBaseline="bottom"; this.Canvas.font=this.Font; this.Canvas.fillText(text,pt.X,pt.Y); } this.DrawArea=function() { var lineStart=null,lineEnd=null; for(var i in this.LinePoint) { var item=this.LinePoint[i]; if (item.Text=='1:8') lineStart=this.LinePoint[i]; else if (item.Text=='8:1') lineEnd=this.LinePoint[i]; } if (!lineStart || !lineEnd) return; this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.moveTo(lineStart.End.X,lineStart.End.Y); this.Canvas.lineTo(lineStart.Start.X,lineStart.Start.Y); this.Canvas.lineTo(lineEnd.End.X,lineEnd.End.Y); this.Canvas.closePath(); this.Canvas.fill(); } //计算线段 this.CalculateLines=function(ptStart,ptEnd,quadrant) { if (!this.Frame) return false; var top=this.Frame.ChartBorder.GetTopEx(); var right=this.Frame.ChartBorder.GetRight(); var bottom=this.Frame.ChartBorder.GetBottom(); const SPLIT_LINE_VALUE=[0.5, 1.0/3, 0.25, 0.125, 2.0/3]; const SPLIT_LINE_X_TITLE=["1:2","1:3","1:4","1:8","2:3"]; const SPLIT_LINE_Y_TITLE=["2:1","3:1","4:1","8:1","3:2"]; var ptLineStart=new Point(); var ptLineEnd=new Point(); ptLineStart.X=ptStart.X; ptLineStart.Y=ptStart.Y; ptLineEnd.X=ptEnd.X; ptLineEnd.Y=ptEnd.Y; var lineWidth=Math.abs(ptStart.X-ptEnd.X); var lineHeight=Math.abs(ptStart.Y-ptEnd.Y); if (quadrant===1) { /* var line={Start:ptLineStart, End:new Point(), IsDottedLine:false}; line.End.X=ptStart.X; line.End.Y=top; this.LinePoint.push(line); line={Start:ptLineStart, End:new Point(), IsDottedLine:false}; line.End.X=right; line.End.Y=ptStart.Y; this.LinePoint.push(line); */ var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd); var line={Start:ptLineStart, End:extendLine.Start, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'}; this.LinePoint.push(line); for(var i in SPLIT_LINE_VALUE) { if (lineWidth>5) { line={Start:ptLineStart, End:null, IsDottedLine:false,PtEnd:new Point(),Text:SPLIT_LINE_X_TITLE[i]}; line.PtEnd.Y=ptEnd.Y; line.PtEnd.X=ptStart.X+lineWidth*SPLIT_LINE_VALUE[i]; var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd); line.End=extendLine.Start; this.LinePoint.push(line); } if (lineHeight>5) { line={Start:ptLineStart, End:null, IsDottedLine:false,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]}; line.PtEnd.Y=ptStart.Y-lineHeight*SPLIT_LINE_VALUE[i]; line.PtEnd.X=ptEnd.X; var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd); line.End=extendLine.Start; this.LinePoint.push(line); } } } else if (quadrant==4) { /* var line={Start:ptLineStart, End:new Point(), IsDottedLine:false}; line.End.X=ptStart.X; line.End.Y=bottom; this.LinePoint.push(line); line={Start:ptLineStart, End:new Point(), IsDottedLine:false}; line.End.X=right; line.End.Y=ptStart.Y; this.LinePoint.push(line); */ var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd); var line={Start:ptLineStart, End:extendLine.End, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'}; this.LinePoint.push(line); for(var i in SPLIT_LINE_VALUE) { if (lineWidth>5) { line={Start:ptLineStart, End:null, IsDottedLine:false,PtEnd:new Point(),Text:SPLIT_LINE_X_TITLE[i]}; line.PtEnd.Y=ptEnd.Y; line.PtEnd.X=ptStart.X+lineWidth*SPLIT_LINE_VALUE[i]; var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd); line.End=extendLine.End; this.LinePoint.push(line); } if (lineHeight>5) { line={Start:ptLineStart, End:null, IsDottedLine:false,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]}; line.PtEnd.Y=ptStart.Y+lineHeight*SPLIT_LINE_VALUE[i]; line.PtEnd.X=ptEnd.X; var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd); line.End=extendLine.End; this.LinePoint.push(line); } } } else return false; return true; } } //阻速线 (高 3等份) function ChartDrawPictureResistanceLine() { this.newMethod=ChartDrawPictureGannFan; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureResistanceLine'; //计算线段 this.CalculateLines=function(ptStart,ptEnd,quadrant) { if (!this.Frame) return false; var top=this.Frame.ChartBorder.GetTopEx(); var right=this.Frame.ChartBorder.GetRight(); var bottom=this.Frame.ChartBorder.GetBottom(); const SPLIT_LINE_VALUE=[1.0/3, 2.0/3]; const SPLIT_LINE_Y_TITLE=["3:1","3:2"]; var ptLineStart=new Point(); var ptLineEnd=new Point(); ptLineStart.X=ptStart.X; ptLineStart.Y=ptStart.Y; ptLineEnd.X=ptEnd.X; ptLineEnd.Y=ptEnd.Y; var lineWidth=Math.abs(ptStart.X-ptEnd.X); var lineHeight=Math.abs(ptStart.Y-ptEnd.Y); if (quadrant===1) { var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd); var line={Start:ptLineStart, End:extendLine.Start, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'}; this.LinePoint.push(line); for(var i in SPLIT_LINE_VALUE) { if (lineHeight>5) { line={Start:ptLineStart, End:null, IsDottedLine:false,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]}; line.PtEnd.Y=ptStart.Y-lineHeight*SPLIT_LINE_VALUE[i]; line.PtEnd.X=ptEnd.X; var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd); line.End=extendLine.Start; this.LinePoint.push(line); } } } else if (quadrant==4) { var extendLine=this.CalculateExtendLinePoint(ptStart,ptEnd); var line={Start:ptLineStart, End:extendLine.End, IsDottedLine:false,PtEnd:ptLineEnd, Text:'1:1'}; this.LinePoint.push(line); for(var i in SPLIT_LINE_VALUE) { if (lineHeight>5) { line={Start:ptLineStart, End:null, IsDottedLine:false,PtEnd:new Point(), Text:SPLIT_LINE_Y_TITLE[i]}; line.PtEnd.Y=ptStart.Y+lineHeight*SPLIT_LINE_VALUE[i]; line.PtEnd.X=ptEnd.X; var extendLine=this.CalculateExtendLinePoint(line.Start,line.PtEnd); line.End=extendLine.End; this.LinePoint.push(line); } } } else return false; return true; } this.DrawArea=function() { var lineStart=null,lineEnd=null; for(var i in this.LinePoint) { var item=this.LinePoint[i]; if (item.Text=='1:1') lineStart=this.LinePoint[i]; else if (item.Text=='3:1') lineEnd=this.LinePoint[i]; } if (!lineStart || !lineEnd) return; this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.moveTo(lineStart.End.X,lineStart.End.Y); this.Canvas.lineTo(lineStart.Start.X,lineStart.Start.Y); this.Canvas.lineTo(lineEnd.End.X,lineEnd.End.Y); this.Canvas.closePath(); this.Canvas.fill(); } } //黄金分割线 function ChartDrawPictureGoldenSection() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureGoldenSectionLine'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Font=14*GetDevicePixelRatio() +"px 微软雅黑"; this.GetSectionData=function() { const GOLDEN_SECTION_DATA= [0,0.236,0.382,0.5,0.618,0.80,1,1.236,1.382,1.5,1.618,1.8,2]; return GOLDEN_SECTION_DATA; } this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint(); if (!drawPoint) return; if (drawPoint.length!=2) return; this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); this.CalculateLines(drawPoint[0],drawPoint[1]); this.ClipFrame(); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End,item.IsDottedLine); } for(var i in this.LinePoint) { var item =this.LinePoint[i]; if (item.Text) this.DrawTitle(item.Start,item.Text); } this.DrawPoint(drawPoint); //画点 this.Canvas.restore(); } this.CalculateLines=function(ptStart,ptEnd) { var sectionData=this.GetSectionData(); var left=this.Frame.ChartBorder.GetLeft(); var right=this.Frame.ChartBorder.GetRight(); var lineHeight=ptStart.Y-ptEnd.Y; for(var i=0;i=0) return value; if (this.CircleData && this.CircleData.R>8) { var triangleX=this.CircleData.X-x; var triangleY=this.CircleData.Y-y; var r=Math.sqrt(triangleX*triangleX+triangleY*triangleY); //计算直径 if (rthis.CircleData.R-8) return 100; } return -1; } } //四边形 function ChartDrawPictureQuadrangle() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureQuadrangle'; this.IsPointIn=this.IsPointIn_XYValue_Line; this.PointCount=3; this.LastPoint; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint({IsCheckX:true, IsCheckY:true}); if (!drawPoint) return; this.AreaColor=IChartDrawPicture.ColorToRGBA(this.LineColor,0.3); var points=drawPoint.slice(0); this.CalculateLines(points); this.ClipFrame(); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End); } this.DrawArea(); this.DrawPoint(points); //画点 this.Canvas.restore(); } this.SetLastPoint=function(obj) { this.LastPoint={X:obj.X,Y:obj.Y}; } this.DrawArea=function() { if (this.LinePoint.length!=4) return; this.Canvas.fillStyle=this.AreaColor; this.Canvas.beginPath(); this.Canvas.moveTo(this.LinePoint[0].Start.X,this.LinePoint[0].Start.Y); this.Canvas.lineTo(this.LinePoint[0].End.X,this.LinePoint[0].End.Y); this.Canvas.lineTo(this.LinePoint[1].End.X,this.LinePoint[1].End.Y); this.Canvas.lineTo(this.LinePoint[2].End.X,this.LinePoint[2].End.Y); this.Canvas.closePath(); this.Canvas.fill(); } this.CalculateLines=function(points) { if (this.PointStatus==2 && this.LastPoint) { var pt=new Point(); pt.X=this.LastPoint.X; pt.Y=this.LastPoint.Y; points[2]=pt; } if (points.length==2) { var linePoint=this.CreateLineData(points[0],points[1]); this.LinePoint.push(linePoint); } else if (points.length==3) { var linePoint=this.CreateLineData(points[0],points[1]); this.LinePoint.push(linePoint); var linePoint=this.CreateLineData(points[1],points[2]); this.LinePoint.push(linePoint); //计算平行线 var xMove=points[2].X-points[1].X; var yMove=points[2].Y-points[1].Y; var pt4=new Point(); //第4个点的坐标 pt4.X=points[0].X+xMove; pt4.Y=points[0].Y+yMove; var linePoint=this.CreateLineData(points[2],pt4); this.LinePoint.push(linePoint); var linePoint=this.CreateLineData(pt4,points[0]); this.LinePoint.push(linePoint); } } } //斐波那契周期线 function ChartDrawPictureFibonacci() { this.newMethod=IChartDrawPicture; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ChartDrawPictureFibonacci'; this.PointCount=1; this.Font=14*GetDevicePixelRatio() +"px 微软雅黑"; this.IsPointIn=this.IsPointIn_XYValue_Line; this.Draw=function() { this.LinePoint=[]; var drawPoint=this.CalculateDrawPoint(); if (!drawPoint) return; this.CalculateLines(); if (this.LinePoint.length<=0) return; this.ClipFrame(); for(var i in this.LinePoint) { var item=this.LinePoint[i]; this.DrawLine(item.Start,item.End); this.DrawTitle(item.Start,item.Title); } this.DrawPoint(drawPoint); //画点 this.Canvas.restore(); } this.DrawTitle=function(pt,text) { this.Canvas.fillStyle=this.LineColor; this.Canvas.textAlign="left"; this.Canvas.textBaseline="top"; this.Canvas.font=this.Font; this.Canvas.fillText(text,pt.X+2,pt.Y+10); } this.CalculateLines=function() { if (this.Status<2) return; if (!this.Frame) return; var data=this.Frame.Data; if (!data) return; var xStart=null; if (this.Status==10) { if (this.Value.length!=1) return; xStart=this.Value[0].XValue; } else { if (this.Point.length!=1) return; xStart=parseInt(this.Frame.GetXData(this.Point[0].X))+data.DataOffset; } var top=this.Frame.ChartBorder.GetTopEx(); var bottom=this.Frame.ChartBorder.GetBottom(); var showCount=this.Frame.XPointCount; const LINE_DATA=[1,2,3,5,8,13,21,34,55,89,144,233]; for(var i=0;i=showCount) continue; var x=this.Frame.GetXFromIndex(xValue-data.DataOffset,false); var line={Start:new Point(), End:new Point(), Title:LINE_DATA[i]}; line.Start.Y=top; line.Start.X=x; line.End.Y=bottom; line.End.X=x; this.LinePoint.push(line); } } } function ChartDrawStorage() { this.DrawData=new Map(); //画图工具数据 key=symbol-Period, value=Map() Key:Guid, Value:{Guid, Symbol, Period, ClassName, Value} this.StorageKey; this.Load=function(key) //从本地读取画图工具 { if (!key) return; this.StorageKey=key; var cacheValue = localStorage[this.StorageKey]; console.log(`[ChartDrawStorage::Save] Load to localStorage, key=${this.StorageKey}, cache=${cacheValue}`); if (!cacheValue) return; if (typeof(cacheValue) != "string") return; var saveData=JSON.parse(cacheValue); for(var i in saveData) { var item=saveData[i]; var drawMap=new Map(); for(var j in item.Value) { var drawItem=item.Value[j]; drawMap.set(drawItem.Key, drawItem.Value); } this.DrawData.set(item.Key,drawMap); } } this.Save=function() //把数据保存到本地 { if (!this.StorageKey) return; var saveData=[]; for(var stock of this.DrawData) { var key=stock[0]; var value=stock[1]; var itemData={ Key:key, Value:[]}; for(var drawItem of value) { itemData.Value.push({Key:drawItem[0], Value:drawItem[1]}); } saveData.push(itemData) } console.log(`[ChartDrawStorage::Save] save to localStorage, key=${this.StorageKey}`); var strData=JSON.stringify(saveData); localStorage[this.StorageKey]=strData; } this.SaveDrawData=function(drawPicture) //保存一个画图工具 { var strKey=drawPicture.Symbol+'-'+drawPicture.Period; var data=drawPicture.ExportStorageData(); if (!data) return; if (this.DrawData.has(strKey)) //更新 { console.log('[ChartDrawStorage::SaveDrawData] Upate: key, drawPicture, data', strKey, drawPicture,data); this.DrawData.get(strKey).set(data.Guid, data); } else //新增 { console.log('[ChartDrawStorage::SaveDrawData] Insert: key, drawPicture, data', strKey, drawPicture,data); var newData=new Map(); newData.set(data.Guid, data); this.DrawData.set(strKey,newData); } console.log('[ChartDrawStorage::SaveDrawData] All draw data: ', this.DrawData); this.Save(); } this.DeleteDrawData=function(drawPicture) //删除一个画图工具 { var strKey=drawPicture.Symbol+'-'+drawPicture.Period; if (!this.DrawData.has(strKey)) return; this.DrawData.delete(strKey); this.Save(); } this.Clear=function() { this.DrawData=new Map(); this.Save(); } this.GetDrawData=function(obj) //获取已有的画图工具数据{Symbol: , Period:, } { var data=[]; var strKey=obj.Symbol+'-'+obj.Period; if (!this.DrawData.has(strKey)) return data; var stockData=this.DrawData.get(strKey); for(var item of stockData) { data.push(item[1]); } return data; } } ///////////////////////////////////////////////////////////////////////////////////////////////////////// // 数据分割 // [0]=Start起始 [1]=End结束 [2]=FixInterval修正的间隔 [3]=Increase // function SplitData() { this.Data=[ [0.000001, 0.000002, 0.000001, 0.0000001], [0.000002, 0.000004, 0.000002, 0.0000002], [0.000004, 0.000005, 0.000004, 0.0000001], [0.000005, 0.00001, 0.000005, 0.0000005], [0.00001, 0.00002, 0.00001, 0.000001], [0.00002, 0.00004, 0.00002, 0.000002], [0.00004, 0.00005, 0.00004, 0.000001], [0.00005, 0.0001, 0.00005, 0.000005], [0.0001, 0.0002, 0.0001, 0.00001], [0.0002, 0.0004, 0.0002, 0.00002], [0.0004, 0.0005, 0.0004, 0.00001], [0.0005, 0.001, 0.0005, 0.00005], [0.001, 0.002, 0.001, 0.0001], [0.002, 0.004, 0.002, 0.0002], [0.004, 0.005, 0.004, 0.0001], [0.005, 0.01, 0.005, 0.0005], [0.01, 0.02, 0.01, 0.001], [0.02, 0.04, 0.02, 0.002], [0.04, 0.05, 0.04, 0.001], [0.05, 0.1, 0.05, 0.005], [0.1, 0.2, 0.1, 0.01], [0.2, 0.4, 0.2, 0.02], [0.4, 0.5, 0.4, 0.01], [0.5, 1, 0.5, 0.05], [1, 2, 0.5, 0.05], [2, 4, 0.5, 0.05], [4, 5, 0.5, 0.05], [5, 10, 0.5, 0.05], [10, 12, 10, 2], [20, 40, 20, 5], [40, 50, 40, 2], [50, 100, 50, 10], [100, 200, 100, 10], [200, 400, 200, 20], [400, 500, 400, 10], [500, 1000, 500, 50], [1000, 2000, 1000, 50], [2000, 4000, 2000, 50], [4000, 5000, 4000, 50], [5000, 10000, 5000, 100], [10000, 20000, 10000, 1000], [20000, 40000, 10000, 1000], [40000, 50000, 10000, 1000], [50000, 100000, 10000, 1000], [100000, 200000, 100000, 10000], [200000, 400000, 100000, 10000], [400000, 500000, 100000, 10000], [500000, 1000000, 100000, 10000], [1000000, 2000000, 1000000, 100000], [2000000, 4000000, 1000000, 100000], [4000000, 5000000, 1000000, 100000], [5000000, 10000000, 1000000, 100000], [10000000, 20000000, 10000000, 1000000], [20000000, 40000000, 10000000, 1000000], [40000000, 50000000, 10000000, 1000000], [50000000, 100000000, 10000000, 1000000], [100000000, 200000000, 100000000, 10000000], [200000000, 400000000, 100000000, 10000000], [400000000, 500000000, 100000000, 10000000], [500000000, 1000000000, 100000000, 10000000], [1000000000, 2000000000, 1000000000, 100000000], [2000000000, 4000000000, 1000000000, 100000000], [4000000000, 5000000000, 1000000000, 100000000], [5000000000, 10000000000, 1000000000, 100000000] ]; this.Find=function(interval) { for(var i in this.Data) { var item =this.Data[i]; if (interval>item[0] && interval<=item[1]) { var result={}; result.FixInterval=item[2]; result.Increase=item[3]; return result; } } return null; } } function PriceSplitData() { this.newMethod=SplitData; //派生 this.newMethod(); delete this.newMethod; this.Data=[ [0.000001, 0.000002, 0.000001, 0.0000001], [0.000002, 0.000004, 0.000002, 0.0000002], [0.000004, 0.000005, 0.000004, 0.0000001], [0.000005, 0.00001, 0.000005, 0.0000005], [0.00001, 0.00002, 0.00001, 0.000001], [0.00002, 0.00004, 0.00002, 0.000002], [0.00004, 0.00005, 0.00004, 0.000001], [0.00005, 0.0001, 0.00005, 0.000005], [0.0001, 0.0002, 0.0001, 0.00001], [0.0002, 0.0004, 0.0002, 0.00002], [0.0004, 0.0005, 0.0004, 0.00001], [0.0005, 0.001, 0.0005, 0.00005], [0.001, 0.002, 0.001, 0.0001], [0.002, 0.004, 0.002, 0.0001], [0.004, 0.005, 0.004, 0.0001], [0.005, 0.01, 0.005, 0.0005], [0.01, 0.02, 0.01, 0.001], [0.02, 0.04, 0.02, 0.001], [0.04, 0.05, 0.04, 0.001], [0.05, 0.1, 0.05, 0.001], [0.1, 0.2, 0.1, 0.01], [0.2, 0.4, 0.2, 0.01], [0.4, 0.5, 0.2, 0.01], [0.5, 0.8, 0.2, 0.01], [0.8, 1, 0.5, 0.01], [1, 2, 0.5, 0.05], [2, 4, 0.5, 0.05], [4, 5, 0.5, 0.05], [5, 10, 0.5, 0.05], [10, 12, 10, 2], [20, 40, 20, 5], [40, 50, 40, 2], [50, 100, 50, 10], [100, 200, 100, 10], [200, 400, 200, 20], [400, 500, 400, 10], [500, 1000, 500, 50], [1000, 2000, 1000, 50], [2000, 4000, 2000, 50], [4000, 5000, 4000, 50], [5000, 10000, 5000, 100], [10000, 20000, 10000, 1000], [20000, 40000, 20000, 2000], [40000, 50000, 40000, 1000], [50000, 100000, 50000, 5000], [100000, 200000, 100000, 10000], [200000, 400000, 200000, 20000], [400000, 500000, 400000, 10000], [500000, 1000000, 500000, 50000], [1000000, 2000000, 1000000, 100000], [2000000, 4000000, 2000000, 200000], [4000000, 5000000, 4000000, 100000], [5000000, 10000000, 5000000, 500000], [10000000, 20000000, 10000000, 1000000], [20000000, 40000000, 20000000, 2000000], [40000000, 50000000, 40000000, 1000000], [50000000, 100000000, 50000000, 5000000], [100000000, 200000000, 100000000, 10000000], [200000000, 400000000, 200000000, 20000000], [400000000, 500000000, 400000000, 10000000], [500000000, 1000000000, 500000000, 50000000], [1000000000, 2000000000, 1000000000, 100000000], [2000000000, 4000000000, 2000000000, 200000000], [4000000000, 5000000000, 4000000000, 100000000], [5000000000, 10000000000, 5000000000, 500000000] ]; } ///////////////////////////////////////////////////////////////////////////// // 全局配置颜色 // // function JSChartResource() { this.TooltipBGColor="rgb(255, 255, 255)"; //背景色 this.TooltipAlpha=0.92; //透明度 this.SelectRectBGColor="rgba(1,130,212,0.06)"; //背景色 // this.SelectRectAlpha=0.06; //透明度 this.UpBarColor="rgb(238,21,21)"; this.DownBarColor="rgb(25,158,0)"; this.UnchagneBarColor="rgb(0,0,0)"; this.Minute={}; this.Minute.VolBarColor="rgb(238,127,9)"; this.Minute.PriceColor="rgb(50,171,205)"; this.Minute.AreaPriceColor='rgba(50,171,205,0.1)'; //价格的面积图 this.Minute.AvPriceColor="rgb(238,127,9)"; this.Minute.BeforeBGColor='rgba(240,240,240,0.7)'; //分钟 集合竞价背景 this.DefaultTextColor="rgb(43,54,69)"; this.DefaultTextFont=14*GetDevicePixelRatio() +'px 微软雅黑'; this.TitleFont=13*GetDevicePixelRatio() +'px 微软雅黑'; this.UpTextColor="rgb(238,21,21)"; this.DownTextColor="rgb(25,158,0)"; this.UnchagneTextColor="rgb(0,0,0)"; this.CloseLineColor='rgb(0,191,255)'; this.CloseLineAreaColor=['rgba(0,191,255,0.8)','rgba(0,191,255,0.2)']; this.FrameBorderPen="rgb(225,236,242)"; this.FrameSplitPen="rgb(225,236,242)"; //分割线 this.FrameDotSplitPen='rgb(105,105,105)'; //分割虚线 this.FrameSplitTextColor="rgb(117,125,129)"; //刻度文字颜色 this.FrameSplitTextFont=14*GetDevicePixelRatio() +"px 微软雅黑"; //坐标刻度文字字体 this.FrameTitleBGColor="rgb(246,251,253)"; //标题栏背景色 this.FrameLatestPrice = { TextColor:'rgb(255,255,255)', //最新价格文字颜色 UpBarColor:"rgb(238,21,21)", //上涨 DownBarColor:"rgb(25,158,0)", //下跌 UnchagneBarColor:"rgb(0,0,0)", //平盘 BGAlpha:0.6 }; this.OverlayFrame={ BolderPen:'rgb(190,190,190)', TitleColor:'rgb(105,105,105)', TitleFont:11*GetDevicePixelRatio() +'px arial', }; this.CorssCursorBGColor="rgb(43,54,69)"; //十字光标背景 this.CorssCursorTextColor="rgb(255,255,255)"; this.CorssCursorTextFont=14*GetDevicePixelRatio() +"px 微软雅黑"; this.CorssCursorPenColor="rgb(130,130,130)"; //十字光标线段颜色 this.LockBGColor = "rgb(220, 220, 220)"; this.LockTextColor = "rgb(210, 34, 34)"; this.Domain="https://opensource.zealink.com"; //API域名 this.CacheDomain="https://opensourcecache.zealink.com"; //缓存域名 this.PyIndexDomain='https://py.zealink.com'; //py指标计算域名 this.KLine={ MaxMin: {Font:12*GetDevicePixelRatio() +'px 微软雅黑',Color:'rgb(43,54,69)'}, //K线最大最小值显示 Info: //信息地雷 { Investor: { ApiUrl:'https://opensource.zealink.com/API/NewsInteract', //互动易 IconFont: { Family:'iconfont', Text:'\ue631' , HScreenText:'\ue684', Color:'#1c65db'} //SVG 文本 }, Announcement: //公告 { ApiUrl:'https://opensource.zealink.com/API/ReportList', IconFont: { Family:'iconfont', Text:'\ue633', HScreenText:'\ue685', Color:'#f5a521' }, //SVG 文本 IconFont2: { Family:'iconfont', Text:'\ue634', HScreenText:'\ue686', Color:'#ed7520' } //SVG 文本 //季报 }, Pforecast: //业绩预告 { ApiUrl:'https://opensource.zealink.com/API/StockHistoryDay', IconFont: { Family:'iconfont', Text:'\ue62e', HScreenText:'\ue687', Color:'#986cad' } //SVG 文本 }, Research: //调研 { ApiUrl:'https://opensource.zealink.com/API/InvestorRelationsList', IconFont: { Family:'iconfont', Text:'\ue632', HScreenText:'\ue688', Color:'#19b1b7' } //SVG 文本 }, BlockTrading: //大宗交易 { ApiUrl:'https://opensource.zealink.com/API/StockHistoryDay', IconFont: { Family:'iconfont', Text:'\ue630', HScreenText:'\ue689', Color:'#f39f7c' } //SVG 文本 }, TradeDetail: //龙虎榜 { ApiUrl:'https://opensource.zealink.com/API/StockHistoryDay', IconFont: { Family:'iconfont', Text:'\ue62f', HScreenText:'\ue68a' ,Color:'#b22626' } //SVG 文本 } }, NumIcon: { Color:'rgb(251,80,80)',Family:'iconfont', Text:[ '\ue649', '\ue63b','\ue640','\ue63d','\ue63f','\ue645','\ue641','\ue647','\ue648','\ue646','\ue636', '\ue635','\ue637','\ue638','\ue639','\ue63a','\ue63c','\ue63e','\ue642','\ue644','\ue643' ] }, TradeIcon: //交易指标 图标 { Family:'iconfont', Buy: { Color:'rgb(255,15,4)', Text:'\ue683', HScreenText:'\ue682'}, Sell: { Color:'rgb(64,122,22)', Text:'\ue681',HScreenText:'\ue680'}, } }; this.Index={}; //指标线段颜色 this.Index.LineColor= [ "rgb(255,174,0)", "rgb(25,199,255)", "rgb(175,95,162)", "rgb(236,105,65)", "rgb(68,114,196)", "rgb(229,0,79)", "rgb(0,128,255)", "rgb(252,96,154)", "rgb(42,230,215)", "rgb(24,71,178)", ]; this.OverlaySymbol={ Random:0 }; //Random 颜色的随机数 this.OverlaySymbol.Color= //叠加股票颜色 [ "rgb(38,198,218)", "rgb(103,58,183)", "rgb(0,191,165)", "rgb(130,177,255)", ]; //历史数据api this.Index.StockHistoryDayApiUrl="https://opensource.zealink.com/API/StockHistoryDay"; //市场多空 this.Index.MarketLongShortApiUrl="https://opensource.zealink.com/API/FactorTiming"; //市场关注度 this.Index.MarketAttentionApiUrl="https://opensource.zealink.com/API/MarketAttention"; //行业,指数热度 this.Index.MarketHeatApiUrl="https://opensource.zealink.com/API/MarketHeat"; //自定义指数热度 this.Index.CustomIndexHeatApiUrl="https://opensource.zealink.com/API/QuadrantCalculate"; //指标不支持信息 this.Index.NotSupport={Font:"14px 微软雅黑", TextColor:"rgb(52,52,52)"}; //画图工具 this.DrawPicture={}; this.DrawPicture.LineColor= [ "rgb(30,144,255)", ]; this.DrawPicture.PointColor= [ "rgb(105,105,105)", ]; this.KLineTrain = { Font:'bold 14px arial', LastDataIcon: {Color:'rgb(0,0,205)',Text:'⬇'}, BuyIcon: {Color:'rgb(0,205,102 )',Text:'B'}, SellIcon: {Color:'rgb(255,127,36 )',Text:'S'}, IconFont: { Family:'iconfont', Buy:{ Text:'\ue64a', HScreenText:'\ue68a' ,Color:'rgb(255,140,0)' }, Sell:{ Text:'\ue64b', HScreenText:'\ue68a' ,Color:'rgb(6,79,18)' }, Last:{ Text:'\ue681', HScreenText:'\ue68a' ,Color:'rgb(55,0,255)' }, } }; //手机端tooltip this.TooltipPaint = { BGColor:'rgba(250,250,250,0.8)', //背景色 BorderColor:'rgb(120,120,120)', //边框颜色 TitleColor:'rgb(120,120,120)', //标题颜色 TitleFont:13*GetDevicePixelRatio() +'px 微软雅黑' //字体 }; //弹幕 this.Barrage= { Font:16*GetDevicePixelRatio() +'px 微软雅黑', //字体 Height:20, Color:'RGB(109,109,109)' } //走势图 信息地雷 this.MinuteInfo={ TextColor: 'rgb(84,143,255)', Font: 14*GetDevicePixelRatio() +'px 微软雅黑', PointColor:'rgb(38,113,254)', LineColor:'rgb(120,167,255)', TextBGColor:'rgba(255,255,255,0.8)' } //自定义风格 this.SetStyle=function(style) { if (style.TooltipBGColor) this.TooltipBGColor = style.TooltipBGColor; if (style.TooltipAlpha) this.TooltipAlpha = style.TooltipAlpha; if (style.SelectRectBGColor) this.SelectRectBGColor = style.SelectRectBGColor; if (style.UpBarColor) this.UpBarColor = style.UpBarColor; if (style.DownBarColor) this.DownBarColor = style.DownBarColor; if (style.UnchagneBarColor) this.UnchagneBarColor = style.UnchagneBarColor; if (style.Minute) { if (style.Minute.VolBarColor) this.Minute.VolBarColor = style.Minute.VolBarColor; if (style.Minute.PriceColor) this.Minute.PriceColor = style.Minute.PriceColor; if (style.Minute.AvPriceColor) this.Minute.AvPriceColor = style.Minute.AvPriceColor; if (style.Minute.AreaPriceColor) this.Minute.AreaPriceColor = style.Minute.AreaPriceColor; } if (style.DefaultTextColor) this.DefaultTextColor = style.DefaultTextColor; if (style.DefaultTextFont) this.DefaultTextFont = style.DefaultTextFont; if (style.TitleFont) this.TitleFont = style.TitleFont; if (style.UpTextColor) this.UpTextColor = style.UpTextColor; if (style.DownTextColor) this.DownTextColor = style.DownTextColor; if (style.UnchagneTextColor) this.UnchagneTextColor = style.UnchagneTextColor; if (style.CloseLineColor) this.CloseLineColor = style.CloseLineColor; if (style.CloseLineAreaColor) this.CloseLineAreaColor = style.CloseLineAreaColor; if (style.FrameBorderPen) this.FrameBorderPen = style.FrameBorderPen; if (style.FrameSplitPen) this.FrameSplitPen = style.FrameSplitPen; if (style.FrameDotSplitPen) this.FrameDotSplitPen = style.FrameDotSplitPen; if (style.FrameSplitTextColor) this.FrameSplitTextColor = style.FrameSplitTextColor; if (style.FrameSplitTextFont) this.FrameSplitTextFont = style.FrameSplitTextFont; if (style.FrameTitleBGColor) this.FrameTitleBGColor = style.FrameTitleBGColor; if (style.FrameLatestPrice) { if (style.FrameLatestPrice.TextColor) this.FrameLatestPrice.TextColor = style.FrameLatestPrice.TextColor; if (style.FrameLatestPrice.UpBarColor) this.FrameLatestPrice.UpBarColor = style.FrameLatestPrice.UpBarColor; if (style.FrameLatestPrice.DownBarColor) this.FrameLatestPrice.DownBarColor = style.FrameLatestPrice.DownBarColor; if (style.FrameLatestPrice.UnchagneBarColor) this.FrameLatestPrice.UnchagneBarColor = style.FrameLatestPrice.UnchagneBarColor; if (style.FrameLatestPrice.BGAlpha) this.FrameLatestPrice.BGAlpha = style.FrameLatestPrice.BGAlpha; } if (style.CorssCursorBGColor) this.CorssCursorBGColor = style.CorssCursorBGColor; if (style.CorssCursorTextColor) this.CorssCursorTextColor = style.CorssCursorTextColor; if (style.CorssCursorTextFont) this.CorssCursorTextFont = style.CorssCursorTextFont; if (style.CorssCursorPenColor) this.CorssCursorPenColor = style.CorssCursorPenColor; if (style.KLine) this.KLine = style.KLine; if (style.Index) { if (style.Index.LineColor) this.Index.LineColor = style.Index.LineColor; if (style.Index.NotSupport) this.Index.NotSupport = style.Index.NotSupport; } if (style.ColorArray) this.ColorArray = style.ColorArray; if (style.DrawPicture) { this.DrawPicture.LineColor = style.DrawPicture.LineColor; this.DrawPicture.PointColor = style.DrawPicture.PointColor; } if (style.TooltipPaint) { if (style.TooltipPaint.BGColor) this.TooltipPaint.BGColor=style.TooltipPaint.BGColor; if (style.TooltipPaint.BorderColor) this.TooltipPaint.BorderColor=style.TooltipPaint.BorderColor; if (style.TooltipPaint.TitleColor) this.TooltipPaint.TitleColor=style.TooltipPaint.TitleColor; if (style.TooltipPaint.TitleFont) this.TooltipPaint.TitleFont=style.TooltipPaint.TitleFont; } if (style.MinuteInfo) { if (style.MinuteInfo.TextColor) this.MinuteInfo.TextColor=style.MinuteInfo.TextColor; if (style.MinuteInfo.Font) this.MinuteInfo.Font=style.MinuteInfo.Font; if (style.MinuteInfo.PointColor) this.MinuteInfo.PointColor=style.MinuteInfo.PointColor; if (style.MinuteInfo.LineColor) this.MinuteInfo.LineColor=style.MinuteInfo.LineColor; if (style.MinuteInfo.TextBGColor) this.MinuteInfo.TextBGColor=style.MinuteInfo.TextBGColor; } } } var g_JSChartResource=new JSChartResource(); ///////////////////////////////////////////////////////////////////////////////// // // // var JSCHART_LANGUAGE_ID= { LANGUAGE_CHINESE_ID:0, LANGUAGE_ENGLISH_ID:1 }; function JSChartLocalization() { this.TextResource=new Map([ //内部tooltip ['Tooltip-Open', {CN:'开:', EN:'O:'}], ['Tooltip-High', {CN:'高:', EN:'H:'}], ['Tooltip-Low', {CN:'低:', EN:'L:'}], ['Tooltip-Close', {CN:'收:', EN:'C:'}], ['Tooltip-Increase', {CN:'幅:', EN:'I:'}], ['Tooltip-Vol', {CN:'量:', EN:'V:'}], ['Tooltip-Amount', {CN:'额:', EN:'A:'}], ['Tooltip-AvPrice', {CN:'均:', EN:'AP:'}], ['Tooltip-Price', {CN:'价:', EN:'P:'}], ['Tooltip-Exchange', {CN:'换:', EN:'E:'}], ['DivTooltip-Open', {CN:'开盘:', EN:'Open:'}], ['DivTooltip-High', {CN:'最高:', EN:'High:'}], ['DivTooltip-Low', {CN:'最低:', EN:'Low:'}], ['DivTooltip-Close', {CN:'收盘:', EN:'Close:'}], ['DivTooltip-Increase', {CN:'涨幅:', EN:'Increase:'}], ['DivTooltip-Vol', {CN:'数量:', EN:'Volume:'}], ['DivTooltip-Amount', {CN:'金额:', EN:'Amount:'}], ['DivTooltip-Exchange', {CN:'换手:', EN:'Exchange:'}], //K线动态标题 ['KTitle-Open', {CN:'开:', EN:'O:'}], ['KTitle-High', {CN:'高:', EN:'H:'}], ['KTitle-Low', {CN:'低:', EN:'L:'}], ['KTitle-Close', {CN:'收:', EN:'C:'}], ['KTitle-Increase', {CN:'幅:', EN:'I:'}], ['KTitle-Vol', {CN:'量:', EN:'V:'}], ['KTitle-Amount', {CN:'额:', EN:'A:'}], ['KTitle-Exchange', {CN:'换:', EN:'E:'}], //走势图动态标题 ['MTitle-Close', {CN:'价:', EN:'C:'}], ['MTitle-AvPrice', {CN:'均:', EN:'AC:'}], ['MTitle-Increase', {CN:'幅:', EN:'I:'}], ['MTitle-Vol', {CN:'量:', EN:'V:'}], ['MTitle-Amount', {CN:'额:', EN:'A:'}], //周期 ['日线', {CN:'日线', EN:'1D'}], ['周线', {CN:'周线', EN:'1W'}], ['月线', {CN:'月线', EN:'1M'}], ['年线', {CN:'年线', EN:'1Y'}], ['1分', {CN:'1分', EN:'1Min'}], ['5分', {CN:'5分', EN:'5Min'}], ['15分', {CN:'15分', EN:'15Min'}], ['30分', {CN:'30', EN:'30Min'}], ['60分', {CN:'60分', EN:'60Min'}], ['季线', {CN:'季线', EN:'1Q'}], ['分笔', {CN:'分笔', EN:'Tick'}], ['2小时', {CN:'2小时', EN:'2H'}], ['4小时', {CN:'4小时', EN:'4H'}], //复权 ['不复权', {CN:'不复权', EN:'No Right'}], ['前复权', {CN:'前复权', EN:'Pro Right'}], ['后复权', {CN:'后复权', EN:'Post Right'}], //week ['日', {CN:'日', EN:'Sun.'}], ['一', {CN:'一', EN:'Mon.'}], ['二', {CN:'二', EN:'Tues.'}], ['三', {CN:'三', EN:'Wed.'}], ['四', {CN:'四', EN:'Thur.'}], ['五', {CN:'五', EN:'Fri.'}], ['六', {CN:'六', EN:'Sat.'}], ['1月', {CN:'1月', EN:'Jan'}], ['2月', {CN:'2月', EN:'Feb'}], ['3月', {CN:'3月', EN:'Mar'}], ['4月', {CN:'4月', EN:'Apr'}], ['5月', {CN:'5月', EN:'May'}], ['6月', {CN:'6月', EN:'Jun'}], ['7月', {CN:'7月', EN:'Jul'}], ['8月', {CN:'8月', EN:'Aug'}], ['9月', {CN:'9月', EN:'Sept'}], ['10月', {CN:'10月', EN:'Oct'}], ['11月', {CN:'11月', EN:'Nov'}], ['12月', {CN:'12月', EN:'Dec'}], ['自定义分钟', {CN:'分', EN:'Min'}], ['自定义日线', {CN:'日', EN:'D'}] ]); this.GetText=function(key,language) { var item=this.TextResource.get(key); if (!item) return ''; switch(language) { case JSCHART_LANGUAGE_ID.LANGUAGE_CHINESE_ID: return item.CN; case JSCHART_LANGUAGE_ID.LANGUAGE_ENGLISH_ID: return item.EN; default: return item.CN; } } this.SetTextResource=function(key,value) { this.TextResource.set(key,value) } }; var g_JSChartLocalization=new JSChartLocalization(); /* 指标列表 指标信息都在这里,不够后面再加字段 */ 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 BenfordIndex()} }], ["自定义指数热度", {IsMainIndex:false, Create:function(){ return new CustonIndexHeatIndex()} , Name:'自定义指数热度'} ], //能图指标 ["能图-趋势", {IsMainIndex:false, Create:function(){ return new LighterIndex1()}, Name:'大盘/个股趋势' }], ["能图-位置研判", {IsMainIndex:false, Create:function(){ return new LighterIndex2()}, Name:'位置研判' }], ["能图-点位研判", {IsMainIndex:false, Create:function(){ return new LighterIndex3()}, Name:'点位研判' }] ] ); return indexMap.get(id); } //////////////////////////////////////////////////////////////////////////////////////////////// // 指标计算方法 // // // function HQIndexFormula() { } //指数平均数指标 EMA(close,10) HQIndexFormula.EMA=function(data,dayCount) { var result = []; var offset=0; if (offset>=data.length) return result; //取首个有效数据 for(;offsetdata.length) return result; var max=-10000; for(var i=n,j=0;idata[max]) max = j; } } result[i] = data[max]; } return result; } HQIndexFormula.LLV=function(data,n) { var result = []; if (n>data.length) return result; var min=-10000; for(var i=n;idata[min]?min:i; } else { for(var j=(min=i-n+1)+1;j<=i;++j) { if(data[j]=data.length) return result; result=data.slice(0,data.length-n); for(var i=0;idata2比较 返回 0/1 数组 HQIndexFormula.ARRAY_GT=function(data,data2) { var result=[]; var IsNumber=typeof(data2)=="number"; if (IsNumber) { for(var i in data) { result[i]=(data[i]>data2 ? 1:0); } } else { var count=Math.max(data.length,data2.length) for(var i=0;idata2[i] ? 1:0; else result[i]=null; } } return result; } //数组 data>=data2比较 返回 0/1 数组 HQIndexFormula.ARRAY_GTE=function(data,data2) { var result=[]; var IsNumber=typeof(data2)=="number"; if (IsNumber) { for(var i in data) { result[i]=(data[i]>=data2 ? 1:0); } } else { var count=Math.max(data.length,data2.length) for(var i=0;i=data2[i] ? 1:0; else result[i]=null; } } return result; } //数组 data=data.length) return result; var i=dayCount; for(;i=data.length) return result; var index=0; for(;indexdata2[index]&&data[index-1]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_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.6; this.LastPoint.X=null; this.LastPoint.Y=null; console.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(); //更新十字光标位子 } } this.OnWheel=function(e) { console.log('[KLineChartContainer::OnWheel]',e); var x = e.clientX-this.UIElement.getBoundingClientRect().left; var y = e.clientY-this.UIElement.getBoundingClientRect().top; var isInClient=false; this.Canvas.beginPath(); this.Canvas.rect(this.Frame.ChartBorder.GetLeft(),this.Frame.ChartBorder.GetTop(),this.Frame.ChartBorder.GetWidth(),this.Frame.ChartBorder.GetHeight()); isInClient=this.Canvas.isPointInPath(x,y); if (isInClient && e.wheelDelta<0) //缩小 { var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0)); if (this.Frame.ZoomDown(cursorIndex)) { this.CursorIndex=cursorIndex.Index; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); } } else if (isInClient && e.wheelDelta>0) //放大 { var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0)); if (this.Frame.ZoomUp(cursorIndex)) { this.CursorIndex=cursorIndex.Index; this.UpdatePointByCursorIndex(); this.UpdataDataoffset(); this.UpdateFrameMaxMin(); this.Draw(); } } if(e.preventDefault) e.preventDefault(); else e.returnValue = false; } //创建 //windowCount 窗口个数 this.Create=function(windowCount) { this.UIElement.JSChartContainer=this; //创建十字光标 this.ChartCorssCursor=new ChartCorssCursor(); this.ChartCorssCursor.Canvas=this.Canvas; this.ChartCorssCursor.StringFormatX=new HQDateStringFormat(); this.ChartCorssCursor.StringFormatY=new HQPriceStringFormat(); this.ChartCorssCursor.StringFormatY.LanguageID=this.LanguageID; //创建等待提示 this.ChartSplashPaint = new ChartSplashPaint(); this.ChartSplashPaint.Canvas = this.Canvas; //创建框架容器 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.TitlePaint.push(titlePaint); } this.UIElement.addEventListener("keydown", OnKeyDown, true); //键盘消息 this.UIElement.addEventListener("wheel", OnWheel, true); //上下滚动消息 } //创建子窗口 this.CreateChildWindow=function(windowCount) { for(var i=0;i=hisData.Data.length) this.CursorIndex=hisData.Data.length-1-dataOffset; if (this.CursorIndex<0) this.CursorIndex=0; //不一定对啊 if (this.CustomShow) //定制显示 1次有效 { this.SetCustomShow(this.CustomShow,hisData); this.CustomShow=null; } } 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 newDataCount=0; if (lastDataCount>0 && hisData.Data.length>lastDataCount) { newDataCount=hisData.Data.length-lastDataCount; console.log(`[KLineChartContainer::UpdateMainData] [count=${lastDataCount}->${hisData.Data.length}], [newDataCount=${newDataCount}]`); } this.ChartPaint[0].Data=hisData; this.ChartPaint[0].Symbol=this.Symbol; 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; } 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.SetCustomShow=function(customShow,hisData) { if (!customShow || !customShow.Date || customShow.Date<20000101) return; var firstDate=customShow.Date; var index=null; for(var i =0;i=firstDate) { index=i; break; } } if (index===null) { console.log(`[KLineChartContainer::SetCustomShow] Can't find first date=${firstDate}`); return; } var count=hisData.Data.length-index; if (customShow.PageSize>0) count=customShow.PageSize; var customShowCount=count; var pageSize=this.GetMaxMinPageSize(); if (count>pageSize.Max) customShowCount=pageSize.Max; else if (count0 && !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.SourceData=sourceData; this.Symbol=data.symbol; this.Name=data.name; this.BindMainData(bindData,this.PageSize); this.Frame.SetSizeChage(true); this.BindInstructionIndexData(bindData); //执行指示脚本 var firstSubFrame; for(var i=0; i0 && bindData.Period<=3) //复权(日线数据才复权) { 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.UpdateMainData(bindData,lastDataCount); this.BindInstructionIndexData(bindData); //执行指示脚本 for(var i=0; i0 && ChartData.IsDayPeriod(bindData.Period,false)) //复权(日线数据才复权) { 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.UpdateMainData(bindData,lastDataCount); this.BindInstructionIndexData(bindData); //执行指示脚本 for(var i=0; i0 && 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.UpdateMainData(bindData,lastDataCount);//更新主图数据 this.UpdateOverlayRealtimeData(data); //更新叠加股票数据 this.BindInstructionIndexData(bindData); //执行指示脚本 for(var i=0; i0 && MARKET_SUFFIX_NAME.IsSHSZStockA(data.symbol)) //复权数据 ,A股才有有复权 { 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; } item.Data=bindData; } } this.RequestMinuteRealtimeData=function() { var self=this; var arySymbol=[self.Symbol]; for(var i in this.OverlayChartPaint) //叠加的股票更新 { var item=this.OverlayChartPaint[i]; if (!item.Symbol) continue; if (!item.MainData) continue; //等待主图股票数据未下载完 if (item.Status!=OVERLAY_STATUS_ID.STATUS_FINISHED_ID) continue; arySymbol.push(item.Symbol); } if (this.NetworkFilter) { var obj= { Name:'KLineChartContainer::RequestMinuteRealtimeData', //类名:: Explain:'当天1分钟K线数据', Request:{ Url:self.RealtimeApiUrl, Data:{ symbol: arySymbol, 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; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: this.RealtimeApiUrl, data: { "field": ["name","symbol","price","yclose","minutecount","minute","date","time"], "symbol": arySymbol, "start": -1 }, type:"post", dataType: "json", async:true, success: function (data) { self.RecvMinuteRealtimeData(data); self.AutoUpdate(); } }); } this.RecvMinuteRealtimeDataV2=function(data) //新版本的 { if (this.IsOnTouch==true) return; //正在操作中不更新数据 var aryMinuteData=KLineChartContainer.JsonDataToMinuteHistoryData(data); if (!aryMinuteData || aryMinuteData.length<=0) return; var lastDataCount=this.GetHistoryDataCount(); //保存下上一次的数据个数 if (!this.SourceData.MergeMinuteData(aryMinuteData)) return; console.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.BindInstructionIndexData(bindData); //执行指示脚本 for(var i=0; i${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)) //复权(日线数据才复权) { 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.UpdateMainData(bindData,lastDataCount); this.UpdateOverlayMinuteRealtimeData(data); //更新叠加股票数据 this.BindInstructionIndexData(bindData); //执行指示脚本 for(var i=0; iresult.MaxRequestDataCount) result.MaxRequestDataCount=lCount; } else if (ChartData.IsMinutePeriod(this.Period,true)) { var date; var lCount=0; for(var i in this.SourceData.Data) { var item=this.SourceData.Data[i]; if (item.Date!=date) ++lCount; date=item.Date; } if (lCount>result.MaxRequestMinuteDayCount) result.MaxRequestMinuteDayCount=lCount; } return result; } //分笔数据 this.RequestTickData=function() { var self=this; self.ChartSplashPaint.IsEnableSplash = true; self.Draw(); //下载缓存文件 var cacheUrl=g_JSChartResource.CacheDomain+'/cache/dealday/today/'+self.Symbol+'.json' if (this.NetworkFilter) { var obj= { Name:'KLineChartContainer::RequestTickData', //类名:: Explain:'当天分笔数据', Request:{ Url:cacheUrl, Data:{ symbol: self.Symbol }, Type:'GET' }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvTickData(data); self.AutoUpdate(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } /* $.ajax({ url: self.TickApiUrl, data:{"symbol":self.Symbol}, type:"post", dataType: "json", async:true, success: function (data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvTickData(data); self.AutoUpdate(); } }); */ JSNetwork.HttpRequest({ url: cacheUrl, data:{"symbol":self.Symbol}, type:"get", dataType: "json", async:true, success: function (data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvTickData(data); self.AutoUpdate(1); }, error: function(http,e) { self.ChartSplashPaint.IsEnableSplash=false; self.AutoUpdate(); //self.RecvError(http,e,param);; } }); } this.RecvTickData=function(data) { var aryDayData=KLineChartContainer.JsonDataToTickData(data); //原始数据 var sourceData=new ChartData(); sourceData.Data=aryDayData; sourceData.DataType=2; //0=日线数据 1=分钟数据 2=分笔数据 //显示的数据 var bindData=new ChartData(); bindData.Data=aryDayData; bindData.Right=this.Right; bindData.Period=this.Period; bindData.DataType=2; //绑定数据 this.SourceData=sourceData; this.Symbol=data.symbol; this.Name=data.name; this.BindMainData(bindData,this.PageSize); this.BindInstructionIndexData(bindData); //执行指示脚本 var firstSubFrame; for(var i=0; i0) lastTime=source[source.length-1].Time; var newCount=0; for(var i in aryDayData) { var item=aryDayData[i]; if (item.Time<=lastTime) continue; source.push(item); ++newCount; } if (newCount<=0) return; //显示的数据 var bindData=new ChartData(); bindData.Data=source; bindData.Right=this.Right; bindData.Period=this.Period; bindData.DataType=2; //绑定数据 this.Symbol=data.symbol; this.Name=data.name; this.UpdateMainData(bindData,lastDataCount); this.BindInstructionIndexData(bindData); //执行指示脚本 for(var i=0; iCUSTOM_DAY_PERIOD_START && period<=CUSTOM_DAY_PERIOD_START) { if (this.SourceData.DataType!=0) isDataTypeChange=true; } else if (period>CUSTOM_MINUTE_PERIOD_START && period<=CUSTOM_MINUTE_PERIOD_END) { if (this.SourceData.DataType!=1) isDataTypeChange=true; } else { switch(period) { case 0: //日线 case 1: //周 case 2: //月 case 3: //年 case 9: //季线 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; case 10: //分笔线 if (this.SourceData.DataType!=2) isDataTypeChange=true; break; } } this.Period=period; this.ReloadChartDrawPicture(); //切换周期了 清空画图工具 if (isDataTypeChange==false && !this.IsApiPeriod) { this.Update(); return; } if (ChartData.IsDayPeriod(this.Period,true)) { this.CancelAutoUpdate(); //先停止定时器 this.AutoUpdateEvent(false,'KLineChartContainer::ChangePeriod'); //切换周期先停止更新 this.ResetOverlaySymbolStatus(); this.RequestHistoryData(); //请求日线数据 this.ReqeustKLineInfoData(); } else if (ChartData.IsMinutePeriod(this.Period,true)) { this.CancelAutoUpdate(); //先停止定时器 this.AutoUpdateEvent(false,'KLineChartContainer::ChangePeriod'); //切换周期先停止更新 this.ResetOverlaySymbolStatus(); this.ReqeustHistoryMinuteData(); //请求分钟数据 } else if (ChartData.IsTickPeriod(this.Period)) { this.CancelAutoUpdate(); //先停止定时器 this.AutoUpdateEvent(false,'KLineChartContainer::ChangePeriod'); this.RequestTickData(); //请求分笔数据 } } //复权切换 this.ChangeRight=function(right) { if (!MARKET_SUFFIX_NAME.IsSHSZStockA(this.Symbol)) return; //A股股票有复权 if (ChartData.IsTickPeriod(this.Period)) return; //分笔没有复权 var upperSymbol=this.Symbol.toUpperCase(); if (MARKET_SUFFIX_NAME.IsBIT(upperSymbol)) return; if (right<0 || right>2) return; if (this.Right==right) return; this.Right=right; this.Update(); } //设置第1屏的起始日期 this.SetFirstShowDate=function(obj) { if (!obj || !obj.Date) return; console.log('[KLineChartContainer::SetFirstShowDate] obj=', obj); var hisData=null; if (!this.Frame.Data) hisData=this.Frame.Data; else hisData=this.Frame.SubFrame[0].Frame.Data; if (!hisData) return; //数据还没有到达 var index=null; for(var i=0;i=obj.Date) { index=i; break; } } if (index===null) { console.log(`[KLineChartContainer::SetFirstShowDate] an't find first date=${obj.Date}`, obj); return; } var count=hisData.Data.length-index; var customShowCount=count; if (obj.PageSize>0) customShowCount=obj.PageSize; var pageSize = this.GetMaxMinPageSize(); if (pageSize.Max < customShowCount) customShowCount = pageSize.Max; else if (pageSize.Min>customShowCount) customShowCount=pageSize.Min; for(var i in this.Frame.SubFrame) //设置一屏显示的数据个数 { var item =this.Frame.SubFrame[i].Frame; item.XPointCount=customShowCount; } hisData.DataOffset=index; this.CursorIndex=0.6; this.LastPoint.X=null; this.LastPoint.Y=null; console.log(`[KLineChartContainer::SetFirstShowDate] dataOffset=${hisData.DataOffset} CursorIndex=${this.CursorIndex} PageSize=${customShowCount}`); this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); this.UpdatePointByCursorIndex(); //更新十字光标位子 } //删除某一个窗口的指标 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; } //显示隐藏主图K线 this.ShowKLine=function(isShow) { 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; var title=this.TitlePaint[1]; if (type==2) //五彩K线 { this.ChartPaint[0].ColorData=instructionData.Data; if (title) title.ColorIndex={Name:instructionData.Name}; } else if (type==1) //专家指示 { this.ChartPaint[0].TradeData={Sell:instructionData.Sell, Buy:instructionData.Buy}; if (title) title.TradeIndex={Name:instructionData.Name} } } this.ChangeInstructionIndex=function(indexName) { let scriptData = new JSIndexScript(); let indexInfo = scriptData.Get(indexName); if (!indexInfo) return; if(indexInfo.InstructionType!=1 && indexInfo.InstructionType!=2) return; indexInfo.ID=indexName; 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; //交易系统数据取消 var title=this.TitlePaint[1]; if (title) { title.TradeIndex=null; title.ColorIndex=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(); } //切换指标 指定切换窗口指标 this.ChangeIndex=function(windowIndex,indexName,option) { var indexItem=JSIndexMap.Get(indexName); if (!indexItem) { //查找系统指标 let scriptData = new JSIndexScript(); let indexInfo = scriptData.Get(indexName); if (!indexInfo) return; if (indexInfo.IsMainIndex) { windowIndex = 0; //主图指标只能在主图显示 } else { if (windowIndex == 0) windowIndex = 1; //幅图指标,不能再主图显示 } 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); } //主图指标 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.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.WindowIndex[windowIndex]=indexItem.Create(); this.CreateWindowIndex(windowIndex); var bindData=this.ChartPaint[0].Data; this.BindIndexData(windowIndex,bindData); this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } this.ChangePyScriptIndex=function(windowIndex,indexData) { this.DeleteIndexPaint(windowIndex); this.WindowIndex[windowIndex]=new PyScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行 var bindData=this.ChartPaint[0].Data; this.BindIndexData(windowIndex,bindData); //执行脚本 this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } this.AddOverlayIndex=function(obj) { var overlay=this.CreateOverlayWindowsIndex(obj); if (!overlay) return; var bindData=this.ChartPaint[0].Data; this.BindOverlayIndexData(overlay,obj.WindowIndex,bindData); this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Draw(); } //创建一个叠加指标 this.CreateOverlayWindowsIndex=function(obj) // {WindowIndex:, IndexName:, Identify:, ShowRightText:} { let indexName=obj.IndexName; let windowIndex=obj.WindowIndex; let scriptData = new JSIndexScript(); let indexInfo = scriptData.Get(indexName); //系统指标 if (!indexInfo) { var indexCustom=JSIndexMap.Get(indexName); //定制指标 if (!indexCustom) { console.warn(`[KLineChartContainer::CreateOverlayIndex] can not find index[${indexName}]`); return null; } } var subFrame=this.Frame.SubFrame[windowIndex]; subFrame.Interval=this.OverlayIndexFrameWidth; var overlayFrame=new OverlayIndexItem(); if (obj.Identify) overlayFrame.Identify=obj.Identify; //由外部指定id var frame= this.ClassName==='KLineChartHScreenContainer' ? new OverlayKLineHScreenFrame() : new OverlayKLineFrame(); frame.Canvas=this.Canvas; frame.MainFrame=subFrame.Frame; frame.ChartBorder=subFrame.Frame.ChartBorder; if (obj.ShowRightText===true) frame.IsShow=true; else if (obj.ShowRightText===false) frame.IsShow=false; frame.YSplitOperator=new FrameSplitY(); frame.YSplitOperator.LanguageID=this.LanguageID; frame.YSplitOperator.FrameSplitData=this.FrameSplitData.get('double'); frame.YSplitOperator.Frame=frame; frame.YSplitOperator.ChartBorder=frame.ChartBorder; frame.YSplitOperator.SplitCount=subFrame.Frame.YSplitOperator.SplitCount; overlayFrame.Frame=frame; if (indexInfo) { 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, }; var scriptIndex=new OverlayScriptIndex(indexData.Name,indexData.Script,indexData.Args,indexData); //脚本执行 scriptIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }; //叠加指标信息 overlayFrame.Script=scriptIndex; } else { var scriptIndex=indexCustom.Create(); scriptIndex.OverlayIndex={ IsOverlay:true, Identify:overlayFrame.Identify, WindowIndex:windowIndex, Frame:overlayFrame }; //叠加指标信息 scriptIndex.Create(this,windowIndex); overlayFrame.Script=scriptIndex; } subFrame.OverlayIndex.push(overlayFrame); return overlayFrame; } this.DeleteOverlayWindowsIndex=function(identify) //删除叠加指标 { var findIndex=null; for(var i in this.Frame.SubFrame) { var item=this.Frame.SubFrame[i]; for(var j in item.OverlayIndex) { var overlayItem=item.OverlayIndex[j]; if (overlayItem.Identify===identify) { item.OverlayIndex.splice(j, 1); findIndex=parseInt(i); break; } } } if (findIndex==null) { console.warn(`[KLineChartContainer::DeleteOverlayWindowsIndex] can't find overlay index. [identify=${identify}]`); return; } var windowsIndex=findIndex+1; var titlePaint=this.TitlePaint[windowsIndex]; if (titlePaint.OverlayIndex.has(identify)) titlePaint.OverlayIndex.delete(identify); this.Draw(); } this.ChangeKLineDrawType=function(drawType) { 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 } for(var i in this.OverlayChartPaint) //叠加K线样式修改 { var item=this.OverlayChartPaint[i]; item.DrawType=this.KLineDrawType; } this.Draw(); } //修改坐标类型 this.ChangeCoordinateType=function(type) { if (!this.Frame && !this.Frame.SubFrame) return; if (!this.Frame.SubFrame.length) return; if (type==2) //反转坐标 { this.Frame.SubFrame[0].Frame.CoordinateType=1; } else if(type==1) { this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=type; } else if (type==0) { this.Frame.SubFrame[0].Frame.CoordinateType=0; this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=0; } else { return; } this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } //设置指标窗口个数 this.ChangeIndexWindowCount=function(count) { if (count<=0) return; if (this.Frame.SubFrame.length==count) return; var currentLength=this.Frame.SubFrame.length; if (currentLength>count) { for(var i=currentLength-1;i>=count;--i) { this.DeleteIndexPaint(i); this.Frame.SubFrame[i].Frame.ClearToolbar(); } this.Frame.SubFrame.splice(count,currentLength-count); this.WindowIndex.splice(count,currentLength-count); //最后一个显示X轴坐标 for(var i=0;icount) { for(var i=currentLength-1;i>=count;--i) { this.Frame.SubFrame[i].Frame.ClearToolbar(); } this.Frame.SubFrame.splice(count,currentLength-count); this.WindowIndex.splice(count,currentLength-count); } else { for(var i=currentLength;i=this.Frame.SubFrame.length) return; var delFrame=this.Frame.SubFrame[id].Frame; this.DeleteIndexPaint(id); this.Frame.SubFrame[id].Frame.ClearToolbar(); 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 in this.ChartDrawPicture) { var item=this.ChartDrawPicture[i]; if (item.Frame==delFrame) continue; aryDrawPicture.push(item); } this.ChartDrawPicture=aryDrawPicture; } this.Frame.SetSizeChage(true); this.UpdateFrameMaxMin(); this.ResetFrameXYSplit(); 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.CreateExtendChart=function(name, option) //创建扩展图形 { var chart; switch(name) { case '筹码分布': chart=new StockChip(); chart.Canvas=this.Canvas; chart.ChartBorder=this.Frame.ChartBorder; chart.ChartFrame=this.Frame; chart.HQChart=this; chart.Left=this.Frame.ChartBorder.Right; //左边间距使用当前框架间距 chart.SetOption(option); this.ExtendChartPaint.push(chart); this.Frame.ChartBorder.Right+=chart.Width; //创建筹码需要增加右边的间距 return chart; case '画图工具': chart=new DrawToolsButton(); chart.Canvas=this.Canvas; chart.ChartBorder=this.Frame.ChartBorder; chart.ChartFrame=this.Frame; chart.HQChart=this; chart.Left=this.Frame.ChartBorder.Right; //左边间距使用当前框架间距 chart.SetOption(option); this.ExtendChartPaint.push(chart); this.Frame.ChartBorder.Right+=chart.Width; //创建筹码需要增加右边的间距 return chart; case 'KLineTooltip': chart=new KLineTooltipPaint(); 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.OnTouchFinished=function() { if (this.CorssCursorTouchEnd===true) //手势离开十字光标消失 { if (this.TouchDrawCount>0) this.DrawDynamicInfo(); return; } for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (item.ClassName==='KLineTooltipPaint') { this.DrawDynamicInfo(); } } } this.GetExtendChartByClassName=function(name) { for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (item.ClassName==name) return { Index:i, Chart:item }; } return null } this.DeleteExtendChart=function(data) { if (data.Index>=this.ExtendChartPaint.length) return; if (this.ExtendChartPaint[data.Index]!=data.Chart) return; if (typeof(data.Chart.Clear)=='function') data.Chart.Clear(); this.ExtendChartPaint.splice(data.Index,1); } //锁|解锁指标 { Index:指标名字,IsLocked:是否要锁上,Callback:回调 } this.LockIndex=function(lockData) { if (!lockData) return; if (!lockData.IndexName) return; for(let i in this.WindowIndex) { let item=this.WindowIndex[i]; if (!item) conintue; if (item.Name==lockData.IndexName) { item.SetLock(lockData); this.Update(); break; } } } 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.SetSizeChage=function(bChanged) { this.Frame.SetSizeChage(bChanged); for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; item.SizeChange=bChanged; } } this.Update=function() { if (!this.SourceData) 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)) //复权(日线数据才复权) { 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); for(var i=0; i0 && MARKET_SUFFIX_NAME.IsSHSZStockA(item.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; } item.Data=bindData; } } this.ReqeustKLineInfoData(); this.CreateChartDrawPictureByStorage(); //创建画图工具 //刷新画图 this.UpdataDataoffset(); //更新数据偏移 this.UpdatePointByCursorIndex(); //更新十字光标位子 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); //叠加指标 for(var i=0;i0) { 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.AddKLineInfo=function(infoName,bUpdate) { var classInfo=JSKLineInfoMap.GetClassInfo(infoName); if (!classInfo) { console.warn("[KLineChartContainer::AddKLineInfo] can't find infoname=", infoName); return; } for(var i in this.ChartInfo) { var item=this.ChartInfo[i]; if (item.ClassName==classInfo.ClassName) //已经存在 return; } var infoItem=JSKLineInfoMap.Get(infoName); if (!infoItem) return; var item=infoItem.Create(); item.MaxReqeustDataCount=this.MaxReqeustDataCount; this.ChartInfo.push(item); if (bUpdate==true) { item.RequestData(this); //信息地雷信息 } } //删除信息地理 this.DeleteKLineInfo=function(infoName) { var classInfo=JSKLineInfoMap.GetClassInfo(infoName); if (!classInfo) { console.warn("[KLineChartContainer::DeleteKLineInfo] can't find infoname=", infoName); return; } for(var i in this.ChartInfo) { var item=this.ChartInfo[i]; if (item.ClassName==classInfo.ClassName) { this.ChartInfo.splice(i,1); this.UpdataChartInfo(); this.Draw(); break; } } } //清空所有的信息地理 this.ClearKLineInfo=function() { if (!this.ChartInfo || this.ChartInfo.length<=0) return; this.ChartInfo=[]; var klinePaint=this.ChartPaint[0]; klinePaint.InfoData=null; this.Draw(); } //增加叠加股票 只支持日线数据 this.OverlaySymbol=function(symbol,option) { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (item.Symbol===symbol) { console.warn(`[KLineChartContainer::OverlaySymbol] overlay symbol=${symbol} exist.`) return false; } } 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; paint.Symbol=symbol; paint.Color=g_JSChartResource.OverlaySymbol.Color[g_JSChartResource.OverlaySymbol.Random%g_JSChartResource.OverlaySymbol.Color.length]; paint.SetOption(option); ++g_JSChartResource.OverlaySymbol.Random; if (this.ChartPaint[0] && this.ChartPaint[0].Data && this.SourceData) paint.MainData=this.ChartPaint[0].Data; //绑定主图数据 this.OverlayChartPaint.push(paint); if (ChartData.IsDayPeriod(this.Period, true)) this.RequestOverlayHistoryData(); //请求日线数据 else if (ChartData.IsMinutePeriod(this.Period,true)) this.RequestOverlayHistoryMinuteData(); //请求分钟历史数据 return true; } this.RequestOverlayHistoryData=function() { if (!this.OverlayChartPaint.length) return; if (!this.SourceData || !this.SourceData.Data) return; //主图数据还没有到完 var self = this; var dataCount=this.GetRequestDataCount(); var firstDate=this.SourceData.Data[0].Date; for(var i in this.OverlayChartPaint) { let item=this.OverlayChartPaint[i]; if (!item.MainData) continue; //等待主图股票数据未下载完 if (item.Status!=OVERLAY_STATUS_ID.STATUS_NONE_ID) continue; let symbol=item.Symbol; if (!symbol) continue; item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID; 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) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOverlayHistoryData(data,item); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } //请求数据 JSNetwork.HttpRequest({ url: this.KLineApiUrl, data: { "field": ["name","symbol","yclose","open","price","high"], "symbol": symbol, "start": -1, "count": dataCount.MaxRequestDataCount }, type:"post", dataType: "json", async:true, success: function (data) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOverlayHistoryData(data,item); } }); } } this.RecvOverlayHistoryData=function(data,paint) { if (paint.IsDelete) return; var aryDayData=KLineChartContainer.JsonDataToHistoryData(data); //原始叠加数据 var sourceData=new ChartData(); sourceData.Data=aryDayData; sourceData.DataType=0; var bindData=new ChartData(); bindData.Data=aryDayData; bindData.Period=this.Period; bindData.Right=this.Right; bindData.DataType=0; if (bindData.Right>0 && MARKET_SUFFIX_NAME.IsSHSZStockA(data.symbol)) //复权数据 ,A股才有有复权 { 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; } paint.Data=bindData; paint.SourceData=sourceData; paint.Title=data.name; paint.Symbol=data.symbol; paint.Status=OVERLAY_STATUS_ID.STATUS_FINISHED_ID; this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=1; //调整为百份比坐标 this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } this.RequestOverlayHistoryMinuteData=function() { if (!this.OverlayChartPaint.length) return; if (!this.SourceData || !this.SourceData.Data) return; //主图数据还没有到完 var self = this; var dataCount=this.GetRequestDataCount(); var firstDate=this.SourceData.Data[0].Date; var firstTime=this.SourceData.Data[0].Time; for(var i in this.OverlayChartPaint) { let item=this.OverlayChartPaint[i]; if (!item.MainData) continue; //等待主图股票数据未下载完 if (item.Status!=OVERLAY_STATUS_ID.STATUS_NONE_ID) continue; let symbol=item.Symbol; if (!symbol) continue; item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID; if (this.NetworkFilter) { var obj= { Name:'KLineChartContainer::RequestOverlayHistoryMinuteData', //类名:: Explain:'叠加股票分钟K线数据', Request:{ Url:self.MinuteKLineApiUrl, Data: { symbol: symbol, count: dataCount.MaxRequestMinuteDayCount,"first":{ date: firstDate, time:firstTime }, field:["name","symbol","yclose","open","price","high",'vol','amount'] }, Type:'POST' }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOveralyHistoryMinuteData(data,item); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } //请求数据 JSNetwork.HttpRequest({ url: this.MinuteKLineApiUrl, data: { "field": ["name","symbol","yclose","open","price","high",'vol','amount'], "symbol": symbol, "start": -1, "count": dataCount.MaxRequestMinuteDayCount }, type:"post", dataType: "json", async:true, success: function (data) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOveralyHistoryMinuteData(data,item); } }); } } this.RecvOveralyHistoryMinuteData=function(data,paint) { var aryDayData=KLineChartContainer.JsonDataToMinuteHistoryData(data); if (!aryDayData) return; //原始叠加数据 var sourceData=new ChartData(); sourceData.Data=aryDayData; sourceData.DataType=1; //0=日线数据 1=分钟数据 var bindData=new ChartData(); bindData.Data=aryDayData; bindData.Period=this.Period; bindData.Right=this.Right; bindData.DataType=1; var aryOverlayData=this.SourceData.GetOverlayMinuteData(bindData.Data); //和主图数据拟合以后的数据 bindData.Data=aryOverlayData; if (ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 { var periodData=bindData.GetPeriodData(bindData.Period); bindData.Data=periodData; } paint.Data=bindData; paint.SourceData=sourceData; paint.Title=data.name; paint.Symbol=data.symbol; paint.Status=OVERLAY_STATUS_ID.STATUS_FINISHED_ID; //数据下载完成 this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=1; //调整为百份比坐标 this.UpdataDataoffset(); //更新数据偏移 this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } this.ResetOverlaySymbolStatus=function() { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; item.Status=OVERLAY_STATUS_ID.STATUS_NONE_ID; } } //取消叠加股票 this.ClearOverlaySymbol=function() { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; item.IsDelete=true; } this.OverlayChartPaint=[]; this.TitlePaint[0].OverlayChartPaint=this.OverlayChartPaint; //绑定叠加 this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=0; //调整一般坐标 this.UpdateFrameMaxMin(); this.Draw(); } //删除一个叠加股票 this.DeleteOverlaySymbol=function(symbol) { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (item.Symbol===symbol) { item.IsDelete=true; this.OverlayChartPaint.splice(i,1); if (this.OverlayChartPaint.length<=0) this.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType=0; //调整一般坐标 this.UpdateFrameMaxMin(); this.Draw(); return true; } } console.warn(`[KLineChartContainer::DeleteOverlaySymbol] overlay symbol=${symbol} not exist.`) return false; } this.RequestFlowCapitalData=function() { if (!this.Symbol) return; if (this.FlowCapitalReady==true) return; if (MARKET_SUFFIX_NAME.IsBIT(this.Symbol)) //数字货币不需要下载流通股本 { console.log(`[KLineChartContainer::RequestFlowCapitalData] symbol=${this.Symbol} not need download data.`); this.FlowCapitalReady=true; return; } var self = this; let fieldList=["name","date","symbol","capital.a"]; if (this.NetworkFilter) { var obj= { Name:'KLineChartContainer::RequestFlowCapitalData', //类名:: Explain:'流通股本数据', Request:{ Url:self.StockHistoryDayApiUrl, Data: { symbol: [this.Symbol], orderfield:'date',field:fieldList }, Type:'POST' }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.RecvFlowCapitalData(data); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } //请求数据 JSNetwork.HttpRequest({ url: this.StockHistoryDayApiUrl, data: { "field": fieldList, "symbol": [this.Symbol], "orderfield":"date" }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvFlowCapitalData(recvData); } }); } this.RecvFlowCapitalData=function(data) { if (!data.stock || data.stock.length!=1) return; let stock=data.stock[0]; var aryData=new Array(); for(let i in stock.stockday) { var item=stock.stockday[i]; let indexData=new SingleData(); indexData.Date=item.date; var financeData=item.capital; if (!financeData) continue; if (financeData.a>0) { indexData.Value=financeData.a; //流通股本(股) aryData.push(indexData); } } if (ChartData.IsMinutePeriod(this.Period,true)) //分钟数据 { var aryFixedData=this.SourceData.GetMinuteFittingFinanceData(aryData); for(let i in this.SourceData.Data) { var item=this.SourceData.Data[i]; item.FlowCapital=aryFixedData[i].Value; } var bindData=this.ChartPaint[0].Data; var newBindData=new ChartData(); newBindData.Data=this.SourceData.Data; if (ChartData.IsMinutePeriod(bindData.Period,false)) //周期数据 { var periodData=newBindData.GetPeriodData(bindData.Period); newBindData.Data=periodData; } bindData.Data=newBindData.Data; } else { var aryFixedData=this.SourceData.GetFittingFinanceData(aryData); for(let i in this.SourceData.Data) { var item=this.SourceData.Data[i]; item.FlowCapital=aryFixedData[i].Value; } var bindData=this.ChartPaint[0].Data; var newBindData=new ChartData(); newBindData.Data=this.SourceData.Data; if (bindData.Right>0) //复权 { var rightData=newBindData.GetRightDate(bindData.Right); newBindData.Data=rightData; } if (ChartData.IsDayPeriod(bindData.Period,false)) //周期数据 { var periodData=newBindData.GetPeriodData(bindData.Period); newBindData.Data=periodData; } bindData.Data=newBindData.Data; } this.FlowCapitalReady=true; var bDraw=false; for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (item.ClassName=='StockChip') { bDraw=true; break; } } if (bDraw) this.Draw(); } //创建画图工具 this.CreateChartDrawPicture=function(name, callback) { var drawPicture=null; switch(name) { case "线段": drawPicture=new ChartDrawPictureLine(); break; case "射线": drawPicture=new ChartDrawPictureHaflLine(); break; case '水平线': drawPicture=new ChartDrawPictureHorizontalLine(); break; case '趋势线': drawPicture=new ChartDrawPictureTrendLine(); break; case "矩形": drawPicture=new ChartDrawPictureRect(); break; case "圆弧线": drawPicture=new ChartDrawPictureArc(); break; case 'M头W底': drawPicture=new ChartDrawPictureWaveMW(); break; case '平行线': drawPicture=new ChartDrawPictureParallelLines(); break; case '平行通道': drawPicture=new ChartDrawPictureParallelChannel(); break; case '价格通道线': drawPicture=new ChartDrawPicturePriceChannel(); break; case '文本': drawPicture=new ChartDrawPictureText(); drawPicture.HQChart=this; break; case '江恩角度线': drawPicture=new ChartDrawPictureGannFan(); break; case '阻速线': drawPicture=new ChartDrawPictureResistanceLine() break; case '黄金分割': drawPicture=new ChartDrawPictureGoldenSection() break; case '百分比线': drawPicture=new ChartDrawPicturePercentage(); break; case '波段线': drawPicture=new ChartDrawPictureWaveBand(); break; case '三角形': drawPicture=new ChartDrawPictureTriangle(); break; case '对称角度': drawPicture=new ChartDrawPictureSymmetryAngle(); break; case '圆': drawPicture=new ChartDrawPictureCircle(); break; case '平行四边形': drawPicture=new ChartDrawPictureQuadrangle(); break; case '斐波那契周期线': drawPicture=new ChartDrawPictureFibonacci(); break; default: { //iconfont 图标 const ICONFONT_LIST=new Map( [ ["icon-arrow_up", { Text:'\ue683', Color:'#318757'}], ["icon-arrow_down", { Text:'\ue681', Color:'#db563e'}], ["icon-arrow_right", { Text:'\ue680', Color:'#318757'}], ["icon-arrow_left", { Text:'\ue682', Color:'#318757'}], ] ); if (ICONFONT_LIST.has(name)) { var item=ICONFONT_LIST.get(name); drawPicture=new ChartDrawPictureIconFont(); drawPicture.FontOption.Family='iconfont'; drawPicture.Text=item.Text; if (item.Color) drawPicture.LineColor=item.Color; break; } } return false; } drawPicture.Canvas=this.Canvas; drawPicture.Status=0; drawPicture.Symbol=this.Symbol; drawPicture.Period=this.Period; if (callback) drawPicture.FinishedCallback=callback; //完成通知上层回调 self=this; drawPicture.Update=function() //更新回调函数 { self.DrawDynamicInfo(); }; this.CurrentChartDrawPicture=drawPicture; //console.log("[KLineChartContainer::CreateChartDrawPicture] ", name,this.CurrentChartDrawPicture); return true; } this.SetChartDrawPictureFirstPoint=function(x,y) { var drawPicture=this.CurrentChartDrawPicture; if (!drawPicture) return false; if (!this.Frame.SubFrame || this.Frame.SubFrame.length<=0) return false; //相对坐标 var xFixed=x-this.UIElement.getBoundingClientRect().left; var yFixed=y-this.UIElement.getBoundingClientRect().top; 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.beginPath(); this.Canvas.rect(left,top,width,height); if (this.Canvas.isPointInPath(xFixed,yFixed)) { 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个点 } //设置第3个点 this.SetChartDrawPictureThirdPoint=function(x,y) { var drawPicture=this.CurrentChartDrawPicture; if (!drawPicture) return false; drawPicture.Point[2]=new Point(); drawPicture.Point[2].X=x-this.UIElement.getBoundingClientRect().left; drawPicture.Point[2].Y=y-this.UIElement.getBoundingClientRect().top; drawPicture.Status=3; //设置第3个点 } //xStep,yStep 移动的偏移量 this.MoveChartDrawPicture=function(xStep,yStep) { var drawPicture=this.CurrentChartDrawPicture; if (!drawPicture) return false; //console.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; //通知上层画好了 if (drawPicture.FinishedCallback) drawPicture.FinishedCallback(drawPicture); if (this.ChartDrawStorage) this.ChartDrawStorage.SaveDrawData(drawPicture); return true; } //注册鼠标右键事件 this.OnRightMenu=function(x,y,e) { if (this.RightMenu) { var frameId=this.Frame.PtInFrame(x,y); e.data={ Chart:this, FrameID:frameId }; this.RightMenu.DoModal(e); } var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CONTEXT_MENU); if (event) { var frameId=this.Frame.PtInFrame(x,y); var data={ X:x, Y:y, Event:e, FrameID:frameId }; event.Callback(event,data,this); } } this.FinishMoveChartDrawPicture=function() { var drawPicture=this.CurrentChartDrawPicture; if (!drawPicture) return false; if (drawPicture.PointCount!=drawPicture.Point.length) return false; drawPicture.Status=10; //完成 drawPicture.PointToValue(); if (this.ChartDrawStorage) this.ChartDrawStorage.SaveDrawData(drawPicture); this.CurrentChartDrawPicture=null; return true; } //清空所有的画线工具 this.ClearChartDrawPicture=function(drawPicture) { if (!drawPicture) { this.ChartDrawPicture=[]; if (this.ChartDrawStorage) this.ChartDrawStorage.Clear(); this.Draw(); } else { for(var i in this.ChartDrawPicture) { if (this.ChartDrawPicture[i]==drawPicture) { if (this.ChartDrawStorage) this.ChartDrawStorage.DeleteDrawData(drawPicture); this.ChartDrawPicture.splice(i,1); this.Draw(); } } } } //重新加载画图工具(切换股票|周期) this.ReloadChartDrawPicture=function() { this.ChartDrawPicture=[]; this.ChartDrawStorageCache; if (this.ChartDrawStorage) { this.ChartDrawStorageCache=this.ChartDrawStorage.GetDrawData( {Symbol:this.Symbol, Period:this.Period} ); } } this.CreateChartDrawPictureByStorage=function() //把缓存(this.ChartDrawStorageCache) 画图工具创建出来 { if (!this.ChartDrawStorageCache || this.ChartDrawStorageCache.length<=0) return; for(var i in this.ChartDrawStorageCache) { var item=this.ChartDrawStorageCache[i]; if (item.FrameID<0 || !this.Frame.SubFrame || this.Frame.SubFrame.length=0; --info.TempID) //信息地雷是倒叙排的 { var infoItem=infoData[info.TempID]; if (infoItem.Date>kItem.Date) break; //信息地雷日期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; } if (typeof(this.WindowIndex[index].ExecuteScript)=='function') { var hisData=this.ChartPaint[0].Data; this.WindowIndex[index].ExecuteScript(this,index,hisData); } else { 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 event=null; if (this.mapEvent.has(JSCHART_EVENT_ID.DBCLICK_KLINE)) event=this.mapEvent.get(JSCHART_EVENT_ID.DBCLICK_KLINE); if (!this.MinuteDialog && !event) return; 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; if (event) { var data={ Tooltip:tooltip, Stock:{Symbol:this.Symbol, Name:this.Name } } event.Callback(event,data,this); } if (this.MinuteDialog) { e.data={Chart:this,Tooltip:tooltip}; this.MinuteDialog.DoModal(e); } } //选中画图工具 出现单个图形设置菜单 this.OnSelectChartPicture=function(chart) { console.log('[KLineChartContainer::OnSelectChartPicture',chart); if (!this.ChartPictureMenu) this.ChartPictureMenu=new ChartPictureSettingMenu(this.UIElement.parentNode); var event={ data: { ChartPicture:chart, HQChart:this}}; this.ChartPictureMenu.DoModal(event); } 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; var self = this; var marketStatus=MARKET_SUFFIX_NAME.GetMarketStatus(this.Symbol); if (marketStatus==0 || marketStatus==3) return; //闭市,盘后 var frequency=this.AutoUpdateFrequency; if (marketStatus==1) //盘前 { setTimeout(function() { self.AutoUpdate(); },frequency); } else if (marketStatus==2) //盘中 { setTimeout(function() { if (ChartData.IsDayPeriod(self.Period,true)) { self.RequestRealtimeData(); //更新最新行情 //self.ReqeustKLineInfoData(); } else if (ChartData.IsMinutePeriod(self.Period,true)) { self.RequestMinuteRealtimeData(); //请求分钟数据 } else if (ChartData.IsTickPeriod(self.Period)) { self.RequestTickRealtimeData(); //请求最新分笔 } },frequency); } } this.GetMaxMinPageSize = function () { let pageSize={}; let width = this.Frame.ChartBorder.GetWidth(); let barWidth = (ZOOM_SEED[ZOOM_SEED.length - 1][0] + ZOOM_SEED[ZOOM_SEED.length - 1][1]); pageSize.Max=parseInt(width / barWidth) - 2; barWidth= (ZOOM_SEED[0][0] + ZOOM_SEED[0][1]); pageSize.Min=parseInt(width / barWidth) - 2; console.log(`[KLineChartContainer::GetMaxMinPageSize] Max=${pageSize.Max} Min=${pageSize.Min}`); return pageSize; } //获取图形控件的状态 this.GetChartStatus=function() { var subFrame=this.Frame.SubFrame[0].Frame; if (!subFrame) return null; var hisData=subFrame.Data; if (!hisData) return null; var status={ KLine:{ }, Zoom:{} }; status.KLine.Count=hisData.Data.length; status.KLine.Offset=hisData.DataOffset; status.KLine.PageSize=subFrame.XPointCount; status.Zoom.Index=subFrame.ZoomIndex; status.Zoom.Max=ZOOM_SEED.length; return status; } //数据拖拽下载 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)) //下载分钟数据 { console.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)) { console.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 }, 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; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: this.DragMinuteKLineApiUrl, data:postData, type:"post", dataType: "json", async:true, success: function(data) { self.RecvDragMinuteData(data); download.Status=0; self.AutoUpdateEvent(true,'KLineChartContainer::RequestDragMinuteData'); //自动更新 self.AutoUpdate(); } }); } this.RecvDragMinuteData=function(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 (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; i0) 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 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; for (var i = 0; i < list.length; ++i) { var item = new HistoryData(); item.Date = list[i][date]; item.Open = list[i][open]; item.YClose = list[i][yclose]; item.Close = list[i][close]; item.High = list[i][high]; item.Low = list[i][low]; if (isSHSZ) item.Vol = list[i][vol]/100; //原始单位股 else item.Vol = list[i][vol]; item.Amount = list[i][amount]; item.Time=list[i][time]; // if (isNaN(item.Open) || item.Open<=0) continue; //停牌的数据剔除 aryDayData.push(item); } // 无效数据处理 for(var i = 0; i < aryDayData.length; ++i) { var minData = aryDayData[i]; if (minData == null) coninue; if (isNaN(minData.Open) || minData.Open <= 0 || isNaN(minData.High) || minData.High <= 0 || isNaN(minData.Low) || minData.Low <= 0 || isNaN(minData.Close) || minData.Close <= 0 || isNaN(minData.YClose) || minData.YClose <= 0) { if (i == 0) { if (minData.YClose > 0) { minData.Open = minData.YClose; minData.High = minData.YClose; minData.Low = minData.YClose; minData.Close = minData.YClose; } } else // 用前一个有效数据填充 { for(var j = i-1; j >= 0; --j) { var minData2 = aryDayData[j]; if (minData2 == null) coninue; if (minData2.Open > 0 && minData2.High > 0 && minData2.Low > 0 && minData2.Close > 0) { if (minData.YClose <= 0) minData.YClose = minData2.Close; minData.Open = minData2.Open; minData.High = minData2.High; minData.Low = minData2.Low; minData.Close = minData2.Close; break; } } } } } return aryDayData; } KLineChartContainer.JsonDataToTickData=function(data) { /* 历史分笔数据格式 var aryDayData=[]; if (!data.deal || !data.day) return aryDayData; var time=data.deal.time; if (!time) return aryDayData; var date=data.date; var amount=data.deal.amount; var flag=data.deal.flag; var price=data.deal.price; var vol=data.deal.vol; var yClose=data.day.yclose; for(var i in time) { var item = new HistoryData(); item.Date = date; item.Low=item.High=item.Close=item.Open = price[i]; item.YClose = yClose; item.Vol = vol[i]; //原始单位股 item.Amount = amount[i]; item.Flag=flag[i]; item.Time=time[i]; if (isNaN(item.Open) || item.Open<=0) continue; //停牌的数据剔除 yClose=item.Close; aryDayData.push(item); } return aryDayData; */ var aryDayData=[]; if (!data.detail) return aryDayData; var date=data.date; var yClose=data.yclose; for(var i in data.detail) { var item = new HistoryData(); var tick=data.detail[i]; if (!tick) continue; item.Date = date; item.Time=tick[0]; item.Low=item.High=item.Close=item.Open = tick[1]; item.YClose = yClose; item.Vol = tick[2]; //原始单位股 item.Amount = tick[3]; item.Flag=tick[4]; if (isNaN(item.Open) || item.Open<=0) continue; //停牌的数据剔除 yClose=item.Close; 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.IsAutoUpdate=true; //是否自动更新行情数据 this.AutoUpdateFrequency=30000; //30秒更新一次数据 this.AutoUpdateTimer; //自动更新定时器 this.TradeDate=0; //行情交易日期 this.DayCount=1; //显示几天的数据 this.DayData; //多日分钟数据 this.LimitPrice; //涨停价格 { Max:null, Min:null }; this.IsShowBeforeData=false; //是否显示盘前数据 (当日) this.BeforeData=null; //盘前数据 this.IsBeforeData=false; //是否支持显示盘前数据 this.IsShowLead=true; //指数是否显示领先指标 this.MinuteApiUrl=g_JSChartResource.Domain+"/API/Stock"; this.HistoryMinuteApiUrl=g_JSChartResource.Domain+'/API/StockMinuteData'; //历史分钟数据 this.StopAutoUpdate=function() { this.CancelAutoUpdate(); if (!this.IsAutoUpdate) return; this.IsAutoUpdate=false; } //手机拖拽 uielement.ontouchstart=function(e) { if(!this.JSChartContainer) return; if(this.JSChartContainer.DragMode==0) return; this.JSChartContainer.IsOnTouch=true; this.JSChartContainer.PhonePinch=null; var jsChart=this.JSChartContainer; if (jsChart.EnableScrollUpDown==false) e.preventDefault(); //上下拖动图形不能阻止事件 if (jsChart.IsPhoneDragging(e)) { var drag= { "Click":{}, "LastMove":{}, //最后移动的位置 }; var touches=jsChart.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 self=this; var T_ShowCorssCursor=function() //临时函数(Temp_) T_开头 { if (jsChart.ChartCorssCursor.IsShow === true) //移动十字光标 { var pixelTatio = GetDevicePixelRatio(); var x = drag.Click.X-self.getBoundingClientRect().left*pixelTatio; var y = drag.Click.Y-self.getBoundingClientRect().top*pixelTatio; jsChart.OnMouseMove(x, y, e); } } if (jsChart.EnableScrollUpDown==true) { this.DragTimer=setTimeout(function() { if (drag.Click.X==drag.LastMove.X && drag.Click.Y==drag.LastMove.Y) { var mouseDrag=jsChart.MouseDrag; jsChart.MouseDrag=null; T_ShowCorssCursor(); jsChart.PreventTouchEvent(e) } }, 800); } this.JSChartContainer.MouseDrag=drag; document.JSChartContainer=this.JSChartContainer; this.JSChartContainer.SelectChartDrawPicture=null; if (jsChart.EnableScrollUpDown==false) T_ShowCorssCursor(); //移动十字光标 } uielement.ontouchmove=function(e) { if(!this.JSChartContainer) return; var touches=jsChart.GetToucheData(e,this.JSChartContainer.IsForceLandscape); if (jsChart.IsPhoneDragging(e)) { var drag=this.JSChartContainer.MouseDrag; if ((drag==null && jsChart.EnableScrollUpDown==true) || (drag && jsChart.EnableScrollUpDown==false)) { var pixelTatio = GetDevicePixelRatio(); var x = touches[0].clientX-this.getBoundingClientRect().left*pixelTatio; var y = touches[0].clientY-this.getBoundingClientRect().top*pixelTatio; this.JSChartContainer.OnMouseMove(x,y,e); } } if (jsChart.EnableScrollUpDown==false) { e.preventDefault(); } else { if (drag==null) { jsChart.PreventTouchEvent(e); //十字光标出来了,阻止消息 } else { clearTimeout(this.DragTimer); //上下推动图片,停止定时器,消息传递下去 this.DragTimer=null; } } }; uielement.ontouchend=function(e) { console.log('[MinuteChartContainer::uielement.ontouchend]',e); this.JSChartContainer.IsOnTouch = false; this.JSChartContainer.OnTouchFinished(); clearTimeout(this.DragTimer); } } //键盘左右移动十字光标 this.OnKeyDown=function(e) { var keyID = e.keyCode ? e.keyCode :e.which; switch(keyID) { case 37: //left this.CursorIndex=parseInt(this.CursorIndex); if (this.CursorIndex<=0.99999) { if (!this.DataMoveLeft()) break; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); } else { --this.CursorIndex; this.UpdatePointByCursorIndex(); this.DrawDynamicInfo(); } break; case 39: //right var xPointcount=0; if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount; else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount; this.CursorIndex=parseInt(this.CursorIndex); if (this.CursorIndex+1>=xPointcount) { if (!this.DataMoveRight()) break; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); } else { //判断是否在最后一个数据上 var data=null; if (this.Frame.Data) data=this.Frame.Data; else data=this.Frame.SubFrame[0].Frame.Data; if (!data) break; if (this.CursorIndex+data.DataOffset+1>=data.Data.length) break; ++this.CursorIndex; this.UpdatePointByCursorIndex(); this.DrawDynamicInfo(); } break; default: return; } //不让滚动条滚动 if(e.preventDefault) e.preventDefault(); else e.returnValue = false; } //注册鼠标右键事件 this.OnRightMenu=function(x,y,e) { if (this.RightMenu) { var frameId=this.Frame.PtInFrame(x,y); e.data={ Chart:this, FrameID:frameId }; this.RightMenu.DoModal(e); } var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_CONTEXT_MENU); if (event) { var frameId=this.Frame.PtInFrame(x,y); var data={ X:x, Y:y, Event:e, FrameID:frameId }; event.Callback(event,data,this); } } this.UpdatePointByCursorIndex=function() { this.LastPoint.X=this.Frame.GetXFromIndex(this.CursorIndex); var index=this.CursorIndex; index=parseInt(index.toFixed(0)); var data=this.Frame.SourceData; if (data.DataOffset+index>=data.Data.length) { return; } var item=data.Data[data.DataOffset+index]; var close=null; if (item.Before) close=item.Before.Close; else close=item.Close this.LastPoint.Y=this.Frame.GetYFromData(close); } //创建 //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.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.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.UIElement.addEventListener("keydown", OnKeyDown, true); //键盘消息 } //创建子窗口 this.CreateChildWindow=function(windowCount) { for(var i=0;i=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.ChangeIndexWindowCount=function(count) { if (count<2) return; //1,2个窗口固定的不能动 if (this.Frame.SubFrame.length==count) return; var currentLength=this.Frame.SubFrame.length; if (currentLength>count) { for(var i=currentLength-1;i>=count;--i) { this.DeleteIndexPaint(i); var item=this.Frame.SubFrame[i].Frame; if (item.ClearToolbar) item.ClearToolbar(); } this.Frame.SubFrame.splice(count,currentLength-count); this.WindowIndex.splice(count,currentLength-count); } else { //创建新的指标窗口 for(var i=currentLength;i10) return; this.DayCount=count; this.ResetOverlaySymbolStatus(); this.RequestData(); } //叠加股票 只支持日线数据 this.OverlaySymbol=function(symbol) { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (item.Symbol==symbol) { console.warn(`[MinuteChartContainer::OverlaySymbol] overlay symbol=${symbol} exist.`); return false; } } 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"; paint.Symbol=symbol; paint.Color=g_JSChartResource.OverlaySymbol.Color[g_JSChartResource.OverlaySymbol.Random%g_JSChartResource.OverlaySymbol.Color.length]; ++g_JSChartResource.OverlaySymbol.Random; if (this.ChartPaint[0].YClose>0 && this.ChartPaint[0].Data) //绑定主图数据 { paint.MainData=this.ChartPaint[0].Data; paint.MainYClose=this.ChartPaint[0].YClose; } this.OverlayChartPaint.push(paint); if (this.DayCount<=1) this.RequestOverlayMinuteData(); //请求数据 else this.RequestOverlayHistoryMinuteData(); return true; } this.ResetOverlaySymbolStatus=function() { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; item.Status=OVERLAY_STATUS_ID.STATUS_NONE_ID; } } //删除一个叠加股票 this.DeleteOverlaySymbol=function(symbol) { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; if (item.Symbol===symbol) { item.IsDelete=true; this.OverlayChartPaint.splice(i,1); this.UpdateFrameMaxMin(); this.Draw(); return true; } } console.warn(`[MinuteChartContainer::DeleteOverlaySymbol] overlay symbol=${symbol} not exist.`) return false; } //取消叠加股票 this.ClearOverlaySymbol=function() { for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; item.IsDelete=true; } this.OverlayChartPaint=[]; this.Frame.SubFrame[0].Frame.YSplitOperator.OverlayChartPaint=this.OverlayChartPaint; this.TitlePaint[0].OverlayChartPaint=this.OverlayChartPaint; //绑定叠加 this.UpdateFrameMaxMin(); this.Draw(); } this.ShowBeforeData=function(isShow) { if (this.IsShowBeforeData==isShow) return; this.IsShowBeforeData=isShow; this.RequestData(); } this.RequestData=function() { if (this.DayCount<=1) this.RequestMinuteData(); else this.RequestHistoryMinuteData(); } this.ChangeDrawType=function(type) { if (this.ChartPaint.length<=0) return; if (type==0) this.ChartPaint[0].IsDrawArea=true; else if (type==1) this.ChartPaint[0].IsDrawArea=false; else return; this.Draw(); } //请求历史分钟数据 this.RequestHistoryMinuteData=function() { var self=this; this.IsBeforeData=false; this.ChartSplashPaint.IsEnableSplash = 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.IsEnableSplash=false; self.RecvHistoryMinuteData(data); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: self.HistoryMinuteApiUrl, data: { "symbol": self.Symbol, "daycount": self.DayCount }, type:"post", dataType: "json", async:true, success: function (data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvHistoryMinuteData(data); } }); } this.RecvHistoryMinuteData=function(data) { 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.RequestOverlayHistoryMinuteData(); this.AutoUpdate(); } 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=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"); } // 盘前数据(A股) this.IsBeforeData=false; if (this.IsShowBeforeData && this.DayCount===1 && MARKET_SUFFIX_NAME.IsSHSZStockA(self.Symbol)) { this.IsBeforeData=true; fields.push('before'); } 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.IsEnableSplash=false; self.RecvMinuteData(data); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: self.MinuteApiUrl, data: { "field": fields, "symbol": [self.Symbol], "start": -1 }, type:"post", dataType: "json", async:true, success: function (data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvMinuteData(data); } }); } this.RecvMinuteData=function(data) { if (this.IsBeforeData) var aryMinuteData=MinuteChartContainer.JsonDataToMinuteData2(data); else var aryMinuteData=MinuteChartContainer.JsonDataToMinuteData(data); if (this.DayCount>1) //多日走势图 { this.UpdateLatestMinuteData(aryMinuteData,data.stock[0].date); this.UpdateHistoryMinuteUI(); this.RequestOverlayMinuteData(); //请求叠加数据 (主数据下载完再下载) this.AutoUpdate(); return; } //原始数据 var sourceData=new ChartData(); sourceData.Data=aryMinuteData; this.TradeDate=data.stock[0].date; this.SourceData=sourceData; this.Symbol=data.stock[0].symbol; this.Name=data.stock[0].name; var yClose=data.stock[0].yclose; var upperSymbol=this.Symbol.toUpperCase(); if (data.stock[0].yclearing && MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol)) yClose=data.stock[0].yclearing; //期货使用前结算价 this.CaclutateLimitPrice(yClose, data.stock[0].limitprice); //计算涨停价格 this.BindMainData(sourceData,yClose); if (this.Frame.SubFrame.length>2) { var bindData=new ChartData(); bindData.Data=aryMinuteData; for(var i=2; i0 && 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) { console.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) }; console.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)); console.log(`[MinuteChartContainer::CaclutateLimitPrice] ${this.Symbol} tofixed(2) max:${this.LimitPrice.Max} min:${this.LimitPrice.Min}`); } //请求叠加数据 (主数据下载完再下载)) this.RequestOverlayMinuteData=function() { var self = this; var date=this.TradeDate; //最后一个交易日期 for(var i in this.OverlayChartPaint) { let item=this.OverlayChartPaint[i]; if (!item.MainData || !(item.MainYClose>0) ) continue; if (item.Status!=OVERLAY_STATUS_ID.STATUS_NONE_ID) continue; var symbol=item.Symbol; if (!symbol) return; item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID; 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) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOverlayMinuteData(data,item); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } //请求数据 JSNetwork.HttpRequest({ url: self.HistoryMinuteApiUrl, data: { "symbol":symbol, "days": [date], }, type:"post", dataType: "json", async:true, success: function (data) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOverlayMinuteData(data,item); } }); } } this.RecvOverlayMinuteData=function(data,paint) { if (paint.IsDelete) return; 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 paint.SourceData) { var item=paint.SourceData[i]; if (item.Date==minuteData.Date) { paint.SourceData[i]=minuteData; var allMinuteData=this.HistoryMinuteDataToArray(paint.SourceData); 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; } paint.Data=sourceData; paint.Title=data.name; paint.Symbol=data.symbol; paint.YClose=yClose; paint.Status=OVERLAY_STATUS_ID.STATUS_FINISHED_ID; this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } this.RequestOverlayHistoryMinuteData=function() { 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; for(var i in this.OverlayChartPaint) { let item=this.OverlayChartPaint[i] var symbol=item.Symbol; if (!symbol) return; if (item.Status!=OVERLAY_STATUS_ID.STATUS_NONE_ID) continue; item.Status=OVERLAY_STATUS_ID.STATUS_REQUESTDATA_ID; 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) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOverlayHistoryMinuteData(data,item); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } JSNetwork.HttpRequest({ url: self.HistoryMinuteApiUrl, data:{ "symbol": symbol, "days": days }, type:"post", dataType: "json", async:true, success: function (data) { item.Status=OVERLAY_STATUS_ID.STATUS_RECVDATA_ID; self.RecvOverlayHistoryMinuteData(data,item); } }); } } this.RecvOverlayHistoryMinuteData=function(data,paint) //叠加历史的分钟数据 { 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; } } paint.SourceData=overlayDayData; var allMinuteData=this.HistoryMinuteDataToArray(overlayDayData); var yClose=overlayDayData[0].YClose; //取最近一个交易日前收盘最为中轴线 //原始数据 var sourceData=new ChartData(); sourceData.Data=allMinuteData; paint.Data=sourceData; paint.Title=data.name; paint.Symbol=data.symbol; paint.YClose=yClose; paint.Status=OVERLAY_STATUS_ID.STATUS_FINISHED_ID; this.UpdateFrameMaxMin(); //调整坐标最大 最小值 this.Frame.SetSizeChage(true); this.Draw(); } 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; 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.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) { //分钟数据 var bindData=new ChartData(); bindData.Data=minuteData.GetClose(); this.ChartPaint[0].Data=bindData; this.ChartPaint[0].YClose=yClose; this.ChartPaint[0].NotSupportMessage=null; this.ChartPaint[0].SourceData=this.IsBeforeData ? minuteData:null; this.ChartPaint[0].IsShowLead=false; this.ChartPaint[0].LeadData=null; if (MARKET_SUFFIX_NAME.IsSHSZIndex(this.Symbol) && this.DayCount==1 && this.IsShowLead) //指数显示领先指标 { var bindLeadData=new ChartData(); bindLeadData.Data=minuteData.GetLead(); this.ChartPaint[0].LeadData=bindLeadData; this.ChartPaint[0].IsShowLead=true; } this.Frame.SubFrame[0].Frame.YSplitOperator.YClose=yClose; this.Frame.SubFrame[0].Frame.YSplitOperator.Data=bindData; this.Frame.Data=this.ChartPaint[0].Data; this.Frame.SourceData=minuteData; //均线 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.SourceData=this.IsBeforeData ? minuteData:null; this.Frame.SubFrame[0].Frame.YSplitOperator.OverlayChartPaint=this.OverlayChartPaint; this.Frame.SubFrame[0].Frame.YSplitOperator.LimitPrice=this.LimitPrice; //成交量 this.ChartPaint[2].Data=minuteData; this.ChartPaint[2].YClose=yClose; 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 && this.ChartCorssCursor.StringFormatY) this.ChartCorssCursor.StringFormatY.YClose=yClose; if (this.ExtendChartPaint[0]) { this.ExtendChartPaint[0].Symbol=this.Symbol; this.ExtendChartPaint[0].Name=this.Name; } var beforeDataCount=0; var isBeforeData=this.IsBeforeData; if (this.DayCount>1) isBeforeData=false; if (isBeforeData) beforeDataCount=15; for(var i in this.OverlayChartPaint) { var item=this.OverlayChartPaint[i]; item.MainData=this.ChartPaint[0].Data; //叠加股票 item.MainYClose=yClose; item.BeforeDataCount=beforeDataCount; //只是集合竞价数据 item.IsBeforeData=isBeforeData; } } //获取子窗口的所有画法 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.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.OnTouchFinished=function() { if (this.CorssCursorTouchEnd===true) //手势离开十字光标消失 { this.DrawDynamicInfo(); return; } /* 以后放日线的tooltip for(var i in this.ExtendChartPaint) { var item=this.ExtendChartPaint[i]; if (item.ClassName==='KLineTooltipPaint') { this.DrawDynamicInfo(); } } */ } 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.HQChartBorder=this.Frame.ChartBorder; 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; } } // 分钟走势图数据 带盘前数据 MinuteChartContainer.JsonDataToMinuteData2=function(data) { var symbol=data.stock[0].symbol; var preClose=data.stock[0].yclose; //前一个数据价格 var preAvPrice=data.stock[0].yclose; //前一个均价 var yClose=data.stock[0].yclose; var aryMinuteData=[]; var stockData=data.stock[0]; var date=stockData.date; //日期 for(var i in stockData.before) { var item=new MinuteData(); var jsData=stockData.before[i]; var time=jsData[0]; item.Before={}; item.Before.Close=jsData[1]; if (!item.Before.Close) item.Before.Close=preClose; else preClose=item.Before.Close; item.Before.Vol=jsData[2]/100; //沪深股票原始单位股 item.Before.Amount=jsData[3]; item.DateTime=date.toString()+" "+time.toString(); item.Date=date; item.Time=time; if (yClose && item.Before.Close) item.Before.Increase=(item.Before.Close-yClose)/yClose*100; //涨幅 (最新价格-昨收)/昨收*100; aryMinuteData.push(item); } for(var i in stockData.minute) { var jsData=stockData.minute[i]; var item=new MinuteData(); if (jsData.price) preClose=jsData.price; if (jsData.avprice) preAvPrice=jsData.avprice; if (jsData.time==925) continue; //去掉9:25的数据 item.Close=jsData.price; item.Open=jsData.open; item.High=jsData.high; item.Low=jsData.low; item.Amount=jsData.amount; item.Vol=jsData.vol/100; //沪深股票原始单位股 item.DateTime=data.stock[0].date.toString()+" "+jsData.time.toString(); item.Date=data.stock[0].date; item.Time=jsData.time; item.Increase=jsData.increase; item.Risefall=jsData.risefall; item.AvPrice=jsData.avprice; //当前没有价格 使用上一个价格填充 if (!item.Close) item.Open=item.High=item.Low=item.Close=preClose; if (!item.AvPrice) item.AvPrice=preAvPrice; if (yClose && item.Close) item.Increase=(item.Close-yClose)/yClose*100; //涨幅 (最新价格-昨收)/昨收*100; aryMinuteData.push(item); } return aryMinuteData; } //API 返回数据 转化为array[] MinuteChartContainer.JsonDataToMinuteData=function(data,isBeforeData) { 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 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; //默认使用外部日期, 但跨天的 走势图使用内部的日期 for(var i in data.stock[0].minute) { var jsData=data.stock[0].minute[i]; var item=new MinuteData(); 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; if (jsData.date>0) date=jsData.date; //分钟数据中有日期 优先使用 item.DateTime=date.toString()+" "+jsData.time.toString(); item.Date=date; item.Time=jsData.time; if (i==0) { item.IsFristData=true; if(isSHSZ) { item.DateTime=data.stock[0].date.toString() + " 0925"; //沪深股票 第1个数据 写死9:25 item.Time=925; } } item.Increase=jsData.increase; item.Risefall=jsData.risefall; item.AvPrice=jsData.avprice; if (IFrameSplitOperator.IsNumber(jsData.lead)) item.Lead=jsData.lead; //领先指标 指数才有 if (!item.Close) //当前没有价格 使用上一个价格填充 { item.Close=preClose; item.Open=item.High=item.Low=item.Close; } if (!item.AvPrice) item.AvPrice=preAvPrice; //价格是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 (isFutures) item.AvPrice=null; //期货均价暂时没有 if (yClose && item.Close) item.Increase=(item.Close-yClose)/yClose*100; //涨幅 (最新价格-昨收)/昨收*100; //均价太大 可能是后台算错了 var checkValue=Math.abs(item.AvPrice-item.Close); //console.log(`[MinuteChartContainer::JsonDataToMinuteData] checkValue=${checkValue}, ${item.Close*0.13} `) if (isSHSZ && checkValue>item.Close*0.13 ) item.AvPrice=preAvPrice; //上次价格 if (jsData.price>0) preClose=jsData.price; if (jsData.avprice>0 && item.AvPrice===jsData.avprice) preAvPrice=jsData.avprice; aryMinuteData[i]=item; } return aryMinuteData; } //多日日线数据API 转化成array[]; MinuteChartContainer.JsonDataToMinuteDataArray=function(data) { var symbol=data.symbol; var upperSymbol=symbol.toUpperCase(); var isSHSZ=MARKET_SUFFIX_NAME.IsSHSZ(upperSymbol); var isFutures=MARKET_SUFFIX_NAME.IsChinaFutures(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; //上一个均价 //var preAvPrice=data.stock[0].yclose; //前一个均价 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]; item.Vol=jsData[5]/100; //原始单位股 item.Amount=jsData[6]; if (70) item.AvPrice=jsData[7]; //均价 item.DateTime=date.toString()+" "+jsData[0].toString(); item.Date=date; item.Time=jsData[0]; 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; if (j==0) //第1个数据 写死9:25 { if (isSHSZ) { item.DateTime=date.toString()+" 0925"; item.Time=925; } 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; //均价太大 可能是后台算错了 if (item.AvPrice && isSHSZ) { var checkValue=Math.abs(item.AvPrice-item.Close); if (checkValue>item.Close*0.13 ) item.AvPrice=preAvPrice; } if (jsData.length>7 && jsData[7]>0 && item.AvPrice===jsData[7]) preAvPrice=jsData[7]; 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/"; this.ClassName='HistoryMinuteChartContainer'; //创建主图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"; JSNetwork.HttpRequest({ url: url, type:"get", dataType: "json", async:true, success: function (data) { self.ChartSplashPaint.IsEnableSplash=false; self.RecvHistoryMinuteData(data); }, error:function(reqeust) { self.ChartSplashPaint.IsEnableSplash=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(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; i0) //当前这一分钟价格为空,使用上一分钟的数据 { 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]; //原始单位股 item.Amount=data.minute.amount[i]; item.DateTime=data.date.toString()+" "+data.minute.time[i].toString(); //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]; //原始单位股 item.Amount=data.minute.amount[i]; item.DateTime=data.date.toString()+" "+data.minute.time[i].toString(); //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.CustomKLineApiUrl=g_JSChartResource.Domain+"/API/IndexCalculate"; //自定义指数计算地址 this.CustomStock; //成分 this.QueryDate={Start:20180101,End:20180627} ; //计算时间区间 this.RequestHistoryData=function() { var self=this; this.ChartSplashPaint.IsEnableSplash = true; this.Draw(); JSNetwork.HttpRequest({ url: this.CustomKLineApiUrl, data: { "stock": self.CustomStock, "Name": self.Symbol, "date": { "startdate":self.QueryDate.Start,"enddate":self.QueryDate.End } }, type:"post", dataType: "json", async:true, success: function (data) { self.ChartSplashPaint.IsEnableSplash = false; self.RecvHistoryData(data); } }); } this.RecvHistoryData=function(data) { var aryDayData=KLineChartContainer.JsonDataToHistoryData(data); //原始数据 var sourceData=new ChartData(); sourceData.Data=aryDayData; sourceData.DataType=0; //0=日线数据 1=分钟数据 //显示的数据 var bindData=new ChartData(); bindData.Data=aryDayData; bindData.Right=this.Right; bindData.Period=this.Period; bindData.DataType=0; if (bindData.Right>0) //复权 { var rightData=bindData.GetRightDate(bindData.Right); bindData.Data=rightData; } 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; i1) //十字光标只能在当前屏移动 { --this.CursorIndex; this.UpdatePointByCursorIndex(); this.DrawDynamicInfo(); this.ShowTooltipByKeyDown(); } break; case 39: //right var xPointcount=0; if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount; else xPointcount=this.Frame.SubFrame[0].Frame.XPointCount; if (this.CursorIndex+1=data.Data.length) break; ++this.CursorIndex; this.UpdatePointByCursorIndex(); this.DrawDynamicInfo(); this.ShowTooltipByKeyDown(); } break; case 38: //up var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0)); if (!this.Frame.ZoomUp(cursorIndex)) break; this.CursorIndex=cursorIndex.Index; this.UpdatePointByCursorIndex(); this.UpdataDataoffset(); this.UpdateFrameMaxMin(); this.Draw(); this.ShowTooltipByKeyDown(); break; case 40: //down var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.CursorIndex-0.5).toFixed(0)); if (!this.Frame.ZoomDown(cursorIndex)) break; this.CursorIndex=cursorIndex.Index; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); this.ShowTooltipByKeyDown(); break; } //不让滚动条滚动 if(e.preventDefault) e.preventDefault(); else e.returnValue = false; } //手机拖拽 uielement.ontouchstart=function(e) { if(!this.JSChartContainer) return; this.JSChartContainer.PhonePinch=null; e.preventDefault(); var jsChart=this.JSChartContainer; if (jsChart.IsPhoneDragging(e)) { var drag= { "Click":{}, "LastMove":{} //最后移动的位置 }; var touches=jsChart.GetToucheData(e,false); 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 (drag.Click.X==drag.LastMove.X && drag.Click.Y==drag.LastMove.Y) //手指没有移动,出现十字光标 { var mouseDrag=jsChart.MouseDrag; jsChart.MouseDrag=null; //移动十字光标 var pixelTatio = GetDevicePixelRatio(); var x = drag.Click.X-uielement.getBoundingClientRect().left*pixelTatio; var y = drag.Click.Y-uielement.getBoundingClientRect().top*pixelTatio; jsChart.OnMouseMove(x,y,e); } document.JSChartContainer=this.JSChartContainer; this.JSChartContainer.SelectChartDrawPicture=null; } else if (jsChart.IsPhonePinching(e)) { var phonePinch= { "Start":{}, "Last":{} }; var touches=jsChart.GetToucheData(e,false); 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.JSChartContainer.PhonePinch=phonePinch; document.JSChartContainer=this.JSChartContainer; this.JSChartContainer.SelectChartDrawPicture=null; } uielement.ontouchmove=function(e) { if(!this.JSChartContainer) return; e.preventDefault(); var touches=jsChart.GetToucheData(e,false); if (jsChart.IsPhoneDragging(e)) { var drag=this.JSChartContainer.MouseDrag; if (drag==null) { var pixelTatio = GetDevicePixelRatio(); var x = touches[0].clientX-this.getBoundingClientRect().left*pixelTatio; var y = touches[0].clientY-this.getBoundingClientRect().top*pixelTatio; this.JSChartContainer.OnMouseMove(x,y,e); } else { } }else if (jsChart.IsPhonePinching(e)) { phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY}; } }; uielement.ontouchend=function(e) { clearTimeout(timeout); } } 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.BindMainData=function(hisData,showCount) //数据到达绑定主图K线数据 { this.ChartPaint[0].Data=hisData; for(var i in this.Frame.SubFrame) { var item =this.Frame.SubFrame[i].Frame; item.XPointCount=showCount; item.Data=this.ChartPaint[0].Data; } 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; if (!this.ChartPaintEx[0]) this.CreateBuySellPaint(); this.ChartPaintEx[0].Data=this.ChartPaint[0].Data; for(var i in this.OverlayChartPaint ) { var item=this.OverlayChartPaint[i]; item.MainData=this.ChartPaint[0].Data; //K线叠加 } var dataOffset=hisData.Data.length-showCount-this.TrainDataCount-20; //随机选一段数据进行训练 if (dataOffset<0) dataOffset=0; this.ChartPaint[0].Data.DataOffset=dataOffset; this.CursorIndex=showCount; if (this.CursorIndex+dataOffset>=hisData.Data.length) this.CursorIndex=dataOffset; this.TrainDataIndex=this.CursorIndex; this.TrainStartEnd.Start=hisData.Data[this.TrainDataIndex+dataOffset-1]; } this.Run=function() { if (this.AutoRunTimer) return; if (this.TrainDataCount<=0) return; var self=this; this.AutoRunTimer=setInterval(function() { if (!self.MoveNextKLineData()) clearInterval(self.AutoRunTimer); }, 1000); } this.MoveNextKLineData=function() { if (this.TrainDataCount<=0) return false; var xPointcount=0; if (this.Frame.XPointCount) xPointcount=this.Frame.XPointCount; //数据个数 if (this.TrainDataIndex+1>=xPointcount) { this.CursorIndex=this.TrainDataIndex; if (!this.DataMoveRight()) return false; this.UpdataDataoffset(); this.UpdatePointByCursorIndex(); this.UpdateFrameMaxMin(); this.Draw(); ++this.TrainDataIndex; --this.TrainDataCount; if (this.TrainDataCount<=0) { this.FinishTrainData(); this.UpdateTrainUICallback(); return false; } this.UpdateTrainUICallback(); return true; } return false; } this.UpdateTrainUICallback=function() { var buySellPaint=this.ChartPaintEx[0]; var lastData=buySellPaint.LastData.Data; this.TrainStartEnd.End=lastData; //老接口 以后会不用 if (this.TrainCallback) this.TrainCallback(this); //新的监听事件 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; //Operator 0=买 1卖 var data={TrainDataCount:this.TrainDataCount, BuySellData:this.BuySellData, Operator:this.GetOperator() , KLine:this.TrainStartEnd}; item.Callback(item,data,this); } this.FinishTrainData=function() { var buySellPaint=this.ChartPaintEx[0]; if (buySellPaint && this.BuySellData.length) //取最后1条数据 看是否卖了 { var lastData=buySellPaint.LastData.Data; var item=this.BuySellData[this.BuySellData.length-1]; if (!item.Sell) { item.Sell={Price:lastData.Close,Date:lastData.Date}; buySellPaint.BuySellData.set(lastData.Date,{Op:1}); } } } this.GetLastBuySellData=function() //取最后1条数据 { var buySellPaint=this.ChartPaintEx[0]; if (!buySellPaint) return null; if (this.BuySellData.length) { var item=this.BuySellData[this.BuySellData.length-1]; return item; } return null; } this.GetOperator=function() //获取当前是卖/买 { var buySellData=this.GetLastBuySellData(); if (buySellData && buySellData.Buy && !buySellData.Sell) return 1; return 0; } this.Stop=function() { if (this.AutoRunTimer!=null) clearInterval(this.AutoRunTimer); this.AutoRunTimer=null; } this.BuyOrSell=function() //模拟买卖 { var buySellPaint=this.ChartPaintEx[0]; var lastData=buySellPaint.LastData.Data; var buySellData=this.GetLastBuySellData(); if (buySellData && buySellData.Buy && !buySellData.Sell) { buySellData.Sell={Price:lastData.Close,Date:lastData.Date}; buySellPaint.BuySellData.set(lastData.Date,{Op:1}); this.MoveNextKLineData(); return; } this.BuySellData.push({ Buy:{Price:lastData.Close,Date:lastData.Date}, Sell:null }); buySellPaint.BuySellData.set(lastData.Date,{Op:0}); this.MoveNextKLineData(); } } //////////////////////////////////////////////////////////////////////////////// // 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(); } uielement.onmousedown=function(e) //鼠标拖拽 { if(!this.JSChartContainer) return; if(this.JSChartContainer.DragMode==0) return; var pixelTatio = GetDevicePixelRatio(); if (this.JSChartContainer.TryClickLock) { var x = (e.clientX-this.getBoundingClientRect().left)*pixelTatio; var y = (e.clientY-this.getBoundingClientRect().top)*pixelTatio; 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.Y0) //放大 { var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.JSChartContainer.CursorIndex-0.5).toFixed(0)); if (!this.JSChartContainer.Frame.ZoomUp(cursorIndex)) return; this.JSChartContainer.CursorIndex=cursorIndex.Index; this.JSChartContainer.UpdatePointByCursorIndex(); this.JSChartContainer.UpdataDataoffset(); this.JSChartContainer.UpdateFrameMaxMin(); this.JSChartContainer.Draw(); this.JSChartContainer.ShowTooltipByKeyDown(); } else //缩小 { var cursorIndex={}; cursorIndex.Index=parseInt(Math.abs(this.JSChartContainer.CursorIndex-0.5).toFixed(0)); if (!this.JSChartContainer.Frame.ZoomDown(cursorIndex)) return; this.JSChartContainer.CursorIndex=cursorIndex.Index; this.JSChartContainer.UpdataDataoffset(); this.JSChartContainer.UpdatePointByCursorIndex(); this.JSChartContainer.UpdateFrameMaxMin(); this.JSChartContainer.Draw(); this.JSChartContainer.ShowTooltipByKeyDown(); } phonePinch.Last={"X":touches[0].pageX,"Y":touches[0].pageY,"X2":touches[1].pageX,"Y2":touches[1].pageY}; } }; uielement.ontouchend=function(e) { this.JSChartContainer.IsOnTouch = false; this.JSChartContainer.OnTouchFinished(); clearTimeout(timeout); } } //创建 //windowCount 窗口个数 this.Create=function(windowCount) { 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; //创建框架容器 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; titlePaint.LanguageID=this.LanguageID; this.TitlePaint.push(titlePaint); } this.UIElement.addEventListener("keydown", OnKeyDown, true); //键盘消息 } //创建子窗口 this.CreateChildWindow=function(windowCount) { for(var i=0;i0) //周期数据 { this.NotSupport(param.HQChart,param.WindowIndex,"不支持周期切换"); param.HQChart.Draw(); return false; } //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.Index.MarketLongShortApiUrl, data: { }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.data.length<=0) return; var aryData=new Array(); for(var i in recvData.data) { var item=recvData.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=null; var isOverlay=this.IsOverlay(); if (isOverlay) paint=this.OverlayIndex.Frame.ChartPaint; else 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; var titleIndex=windowIndex+1; //指定[0,9] if (isOverlay) { this.OverlayIndex.Frame.Frame.YSpecificMaxMin={Max:9,Min:0,Count:3}; var titlePaint=hqChart.TitlePaint[titleIndex]; var titleInfo={ Data:[], Title:'' }; titlePaint.OverlayIndex.set(this.OverlayIndex.Identify,titleInfo); for(var i in paint) { var titleData=new DynamicTitleData(paint[i].Data,this.Index[i].Name,this.Index[i].LineColor); if (i>0) titleData.DataType="StraightLine"; titlePaint.OverlayIndex.get(this.OverlayIndex.Identify).Data[i]=titleData; } } else { hqChart.Frame.SubFrame[windowIndex].Frame.YSpecificMaxMin={Max:9,Min:0,Count:3}; 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"; } } return true; } } //市场择时 function MarketTimingIndex() { this.newMethod=BaseIndex; //派生 this.newMethod('Market-Timing'); delete this.newMethod; this.Index=new Array( new IndexInfo("因子择时",null) ); this.TimingData; //择时数据 this.TitleColor=g_JSChartResource.FrameSplitTextColor this.Create=function(hqChart,windowIndex) { var frame=null; var isOverlay=this.IsOverlay(); if (isOverlay) frame=this.OverlayIndex.Frame.Frame; else frame=hqChart.Frame.SubFrame[windowIndex].Frame; for(var i in this.Index) { var paint=new ChartMACD(); paint.Canvas=hqChart.Canvas; paint.Name=this.Name+"-"+i.toString(); paint.ChartBorder=frame.ChartBorder; paint.ChartFrame=frame; if (isOverlay) this.OverlayIndex.Frame.ChartPaint.push(paint); else 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; } //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.Index.MarketLongShortApiUrl, data: { }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.data.length<=0) return; var aryData=new Array(); for(var i in recvData.data) { var item=recvData.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=null; var isOverlay=this.IsOverlay(); if (isOverlay) paint=this.OverlayIndex.Frame.ChartPaint; else 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; if (isOverlay) { var titlePaint=hqChart.TitlePaint[titleIndex]; var titleInfo={ Data:[], Title:'' }; titlePaint.OverlayIndex.set(this.OverlayIndex.Identify,titleInfo); for(var i in paint) { var titleData=new DynamicTitleData(paint[i].Data,this.Index[i].Name,this.Index[i].LineColor); titleData.StringFormat=STRING_FORMAT_TYPE.THOUSANDS; titleData.FloatPrecision=0; titlePaint.OverlayIndex.get(this.OverlayIndex.Identify).Data[i]=titleData; } } else { 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; } } return true; } } //市场关注度 function MarketAttentionIndex() { this.newMethod=BaseIndex; //派生 this.newMethod('Market-Attention'); 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) { var frame=null; var isOverlay=this.IsOverlay(); if (isOverlay) frame=this.OverlayIndex.Frame.Frame; else frame=hqChart.Frame.SubFrame[windowIndex].Frame; for(var i in this.Index) { var paint=new ChartMACD(); //柱子 paint.Canvas=hqChart.Canvas; paint.Name=this.Name+"-"+i.toString(); paint.ChartBorder=frame.ChartBorder; paint.ChartFrame=frame; if (isOverlay) this.OverlayIndex.Frame.ChartPaint.push(paint); else hqChart.ChartPaint.push(paint); } } //调整框架 this.SetFrame=function(hqChart,windowIndex,hisData) { var isOverlay=this.IsOverlay(); if (isOverlay) this.OverlayIndex.Frame.Frame.YSpecificMaxMin={Max:6,Min:0,Count:3}; else 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; } //请求数据 JSNetwork.HttpRequest({ url: this.ApiUrl, data: { "symbol":param.HQChart.Symbol, "startdate":20100101, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,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(); } this.BindData=function(hqChart,windowIndex,hisData) { var paint=null; var isOverlay=this.IsOverlay(); if (isOverlay) paint=this.OverlayIndex.Frame.ChartPaint; else 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; if (isOverlay) { var titlePaint=hqChart.TitlePaint[titleIndex]; var titleInfo={ Data:[], Title:'' }; titlePaint.OverlayIndex.set(this.OverlayIndex.Identify,titleInfo); for(var i in paint) { var titleData=new DynamicTitleData(paint[i].Data,this.Index[i].Name,this.Index[i].LineColor); titleData.StringFormat=STRING_FORMAT_TYPE.THOUSANDS; titleData.FloatPrecision=0; titlePaint.OverlayIndex.get(this.OverlayIndex.Identify).Data[i]=titleData; } } else { 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; } } return true; } } /* 行业,指数热度 */ function MarketHeatIndex() { this.newMethod=BaseIndex; //派生 this.newMethod('Market-Heat'); 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) { var frame=null; var isOverlay=this.IsOverlay(); if (isOverlay) frame=this.OverlayIndex.Frame.Frame; else frame=hqChart.Frame.SubFrame[windowIndex].Frame; 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=frame.ChartBorder; paint.ChartFrame=frame; if (isOverlay) this.OverlayIndex.Frame.ChartPaint.push(paint); else 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; } //请求数据 JSNetwork.HttpRequest({ url: this.ApiUrl, data: { "symbol":param.HQChart.Symbol, "startdate":20100101, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,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=null; var isOverlay=this.IsOverlay(); if (isOverlay) paint=this.OverlayIndex.Frame.ChartPaint; else 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; if (isOverlay) { var titlePaint=hqChart.TitlePaint[titleIndex]; var titleInfo={ Data:[], Title:'' }; titlePaint.OverlayIndex.set(this.OverlayIndex.Identify,titleInfo); 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; var titleData=new DynamicTitleData(paint[i].Data,name,this.Index[i].LineColor); titleData.StringFormat=STRING_FORMAT_TYPE.DEFAULT; titleData.FloatPrecision=2; titlePaint.OverlayIndex.get(this.OverlayIndex.Identify).Data[i]=titleData; } } else { 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].Explain="热度说明"; 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; } //请求数据 JSNetwork.HttpRequest({ 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], }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.data==null || recvData.data.length<0) return; //console.log(recvData.data); var aryData=new Array(); for(let i in recvData.data) { let item=recvData.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(50,205,50)', Title: '热度1', TitleColor:'rgb(245,255 ,250)'}, { Value: 0.2, Value2: 0.4, Color: 'rgb(255,140,0)', Title: '热度2', TitleColor:'rgb(245,255 ,250)'}, { Value: 0.4, Value2: 0.8, Color: 'rgb(255,106,106)', Title: '热度3', TitleColor:'rgb(245,255 ,250)'}, { Value: 0.8, Value2: 1, Color: 'rgb(208, 32 ,144)', Title: '热度4', 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下线 , 上线,下线 ,2, 0),COLORRED,LINETHICK2; STICKLINE(下线>上线,上线,下线,2,0),COLORBLUE,LINETHICK2; */ function LighterIndex1() { this.newMethod=BaseIndex; //派生 this.newMethod('Lighter-Trend'); delete this.newMethod; this.Index=new Array( new IndexInfo("STICKLINE",null), new IndexInfo('STICKLINE',null) ); this.Index[0].LineColor='rgb(255,0,0)'; this.Index[1].LineColor='rgb(0,0,255)'; this.Create=function(hqChart,windowIndex) { for(var i in this.Index) { var paint=new ChartStickLine(); paint.Canvas=hqChart.Canvas; paint.Name=this.Name; paint.Name=this.Name+'-'+i.toString(); paint.Color=this.Index[i].LineColor; paint.LineWidth=2; paint.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; paint.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; hqChart.ChartPaint.push(paint); } } this.BindData=function(hqChart,windowIndex,hisData) { var paint=hqChart.GetChartPaint(windowIndex); if (paint.length!=2) return false; var closeData=hisData.GetClose(); var upData=HQIndexFormula.SMA(closeData,6.5,1); var downData=HQIndexFormula.SMA(closeData,13.5,1); var stickLine=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(upData,downData),upData,downData);; var stickLine2=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(downData,upData),upData,downData);; paint[0].Data.Data=stickLine; paint[1].Data.Data=stickLine2; var titleIndex=windowIndex+1; hqChart.TitlePaint[titleIndex].Title="大盘/个股 趋势函数"; return true; } } /* 位置研判函数 N:=34;M:=3; 28,COLORFFFFFF; STICKLINE(C>0,0,2,5,0),COLOR00008A; STICKLINE(C>0,2,5,5,0),COLOR85008A; STICKLINE(C>0,5,10,5,0),COLOR657600; STICKLINE(C>0,10,21.5,5,0),COLOR690079; STICKLINE(C>0,21.5,23,5,0),COLOR79B715; STICKLINE(C>0,23,28,5,0),COLOR00008A; VAR1:=EMA(100*(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N)),M)/4,COLORFFFF00,LINETHICK2; 财貌双拳:VAR1,COLORFFFF00,LINETHICK2; DRAWTEXT(CURRBARSCOUNT=128,1,'底部区域'),COLOR00FFFF; DRAWTEXT(CURRBARSCOUNT=128,3.5,'介入区域'),COLOR00FFFF; DRAWTEXT(CURRBARSCOUNT=128,7.5,'稳健区域'),COLOR00FFFF; DRAWTEXT(CURRBARSCOUNT=128,16,'高位区域'),COLOR00FFFF; DRAWTEXT(CURRBARSCOUNT=128,22,'风险区域'),COLOR0000FF; DRAWTEXT(CURRBARSCOUNT=128,25.5,'顶部区域'),COLORFF00FF; */ function LighterIndex2() { this.newMethod=BaseIndex; //派生 this.newMethod('位置研判函数'); delete this.newMethod; this.Index=new Array( new IndexInfo("STICKLINE",34), new IndexInfo('STICKLINE',3), new IndexInfo('STICKLINE',null), new IndexInfo('STICKLINE',null), new IndexInfo('STICKLINE',null), new IndexInfo('STICKLINE',null), new IndexInfo('LINE',null), new IndexInfo('TEXT',null) ); this.Index[0].LineColor='rgb(0,0,138)'; this.Index[1].LineColor='rgb(133,0,138)'; this.Index[2].LineColor='rgb(101,118,0)'; this.Index[3].LineColor='rgb(105,0,121)'; this.Index[4].LineColor='rgb(121,183,21)'; this.Index[5].LineColor='rgb(0,0,138)'; this.Index[6].LineColor='rgb(255,0,0)'; this.Create=function(hqChart,windowIndex) { for(var i in this.Index) { var paint=null; if (this.Index[i].Name=='LINE') { paint=new ChartLine(); paint.Color=this.Index[i].LineColor; } else if (this.Index[i].Name=='TEXT') { paint=new ChartText(); } else { paint=new ChartStickLine(); paint.Color=this.Index[i].LineColor; paint.LineWidth=5; } paint.Canvas=hqChart.Canvas; paint.Name=this.Name; 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.BindData=function(hqChart,windowIndex,hisData) { var paint=hqChart.GetChartPaint(windowIndex); if (paint.length!=this.Index.length) return false; var closeData=hisData.GetClose(); var highData=hisData.GetHigh(); var lowData=hisData.GetLow(); paint[0].Data.Data=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(closeData,0),0,2); paint[1].Data.Data=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(closeData,0),2,5); paint[2].Data.Data=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(closeData,0),5,10); paint[3].Data.Data=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(closeData,0),10,21.5); paint[4].Data.Data=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(closeData,0),21.5,23,5); paint[5].Data.Data=HQIndexFormula.STICKLINE(HQIndexFormula.ARRAY_GT(closeData,0),23,28,5); //VAR1:=EMA(100*(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N)),M)/4 var lineData=HQIndexFormula.ARRAY_DIVIDE( HQIndexFormula.EMA( HQIndexFormula.ARRAY_MULTIPLY( HQIndexFormula.ARRAY_DIVIDE( HQIndexFormula.ARRAY_SUBTRACT(closeData,HQIndexFormula.LLV(lowData,this.Index[0].Param)), HQIndexFormula.ARRAY_SUBTRACT(HQIndexFormula.HHV(highData,this.Index[0].Param),HQIndexFormula.LLV(lowData,this.Index[0].Param)) ), 100), this.Index[1].Param), 4 ); paint[6].Data.Data=lineData; //DRAWTEXT(CURRBARSCOUNT=128,1,'底部区域'),COLOR00FFFF; //DRAWTEXT(CURRBARSCOUNT=128,3.5,'介入区域'),COLOR00FFFF; //DRAWTEXT(CURRBARSCOUNT=128,7.5,'稳健区域'),COLOR00FFFF; //DRAWTEXT(CURRBARSCOUNT=128,16,'高位区域'),COLOR00FFFF; //DRAWTEXT(CURRBARSCOUNT=128,22,'风险区域'),COLOR0000FF; //DRAWTEXT(CURRBARSCOUNT=128,25.5,'顶部区域'),COLORFF00FF; var TextData=new Array(); TextData[0]={Value:1, Message:'底部区域',Color:'rgb(0,255,255)',Position:'Left'}; TextData[1]={Value:3.5, Message:'介入区域',Color:'rgb(0,255,255)',Position:'Left'}; TextData[2]={Value:7.5, Message:'稳健区域',Color:'rgb(0,255,255)',Position:'Left'}; TextData[3]={Value:16, Message:'高位区域',Color:'rgb(0,255,255)',Position:'Left'}; TextData[4]={Value:22, Message:'风险区域',Color:'rgb(0,0,255)',Position:'Left'}; TextData[5]={Value:25.5,Message:'顶部区域',Color:'rgb(255,0,255)',Position:'Left'}; paint[7].Data.Data=TextData; var titleIndex=windowIndex+1; hqChart.TitlePaint[titleIndex].Data[0]=new DynamicTitleData(paint[6].Data,"财貌双拳",paint[6].Color); hqChart.TitlePaint[titleIndex].Title=this.FormatIndexTitle(); return true; } } /* py指标 服务器端执行 */ function PyScriptIndex(name,script,args,option) { this.newMethod=BaseIndex; //派生 this.newMethod(name); delete this.newMethod; this.Script=script; //脚本 this.Arguments=[]; //参数 this.OutVar=[]; //输出数据 this.ApiUrl=g_JSChartResource.PyIndexDomain+'/hq/code'; if (args) this.Arguments=args; this.RequestData=function(hqChart,windowIndex,hisData) { this.OutVar=[]; var self = this; var param= { HQChart:hqChart, WindowIndex:windowIndex, HistoryData:hisData }; //参数 var strParam=''; for(let i in this.Arguments) { if (strParam.length>0) strParam+=','; var item=this.Arguments[i]; strParam+='"'+item.Name+'"'+':'+item.Value; } strParam='{'+strParam+'}'; var indexParam=JSON.parse(strParam); var data=JSON.stringify( { code:this.Script, //脚本 symbol:param.HQChart.Symbol, //股票代码 period:param.HQChart.Period, //周期 0=日线 1=周线 2=月线 3=年线 4=1分钟 5=5分钟 6=15分钟 7=30分钟 8=60分钟 right:param.HQChart.Right, //复权 0 不复权 1 前复权 2 后复权 params:indexParam, //指标参数 numcount:hqChart.MaxReqeustDataCount, }); //请求数据 JSNetwork.HttpRequest({ url: this.ApiUrl, data:data, type:"post", dataType: "json", contentType:' application/json; charset=utf-8', async:true, success: function (recvData) { self.RecvData(recvData,param); }, complete:function(h) { //console.log(h); }, error: function(http,e) { self.RecvError(http,e,param);; } }); return true; } this.RecvError=function(http,e,param) { console.log("[PyScriptIndex::RecvError] error",e); if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback(e); } this.RecvData=function(recvData,param) { if (recvData.code!=0) { console.log("[PyScriptIndex::RecvData] failed.", recvData); if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback(recvData.msg); return; //失败了 } console.log('[PyScriptIndex::RecvData] recv data.',recvData); var aryDate=recvData.date; for(var i in recvData.data) { var item=recvData.data[i]; var indexData=[]; for(var j=0;j=item.data.length) continue; var indexItem=new SingleData(); //单列指标数据 indexItem.Date=aryDate[j]; indexItem.Value=item.data[j]; indexData.push(indexItem); } var aryFittingData=param.HistoryData.GetFittingData(indexData); //数据和主图K线拟合 var bindData=new ChartData(); bindData.Data=aryFittingData; bindData.Period=param.HQChart.Period; //周期 bindData.Right=param.HQChart.Right; //复权 var indexInfo={Name:item.name,Type:item.graph,LineWidth:item.width,Data:bindData.GetValue(),Color:item.color}; this.OutVar.push(indexInfo); } this.BindData(param.HQChart,param.WindowIndex,param.HistoryData); //把数据绑定到图形上 param.HQChart.UpdataDataoffset(); //更新数据偏移 param.HQChart.UpdateFrameMaxMin(); //调整坐标最大 最小值 param.HQChart.Draw(); } this.BindData=function(hqChart,windowIndex,hisData) { hqChart.DeleteIndexPaint(windowIndex); //清空指标图形 for(let i in this.OutVar) { let item=this.OutVar[i]; switch(item.Type) { case 'line': this.CreateLine(hqChart,windowIndex,item,i); break; case 'colorstick': //上下柱子 this.CreateColorStock(hqChart,windowIndex,item,i); break; } } var titleIndex=windowIndex+1; hqChart.TitlePaint[titleIndex].Title=this.Name; //这是指标名称 let indexParam=''; //指标参数 for(let i in this.Arguments) { let item=this.Arguments[i]; if (indexParam.length>0) indexParam+=','; indexParam+=item.Value.toString(); } if (indexParam.length>0) hqChart.TitlePaint[titleIndex].Title=this.Name+'('+indexParam+')'; return true; } this.CreateLine=function(hqChart,windowIndex,varItem,id) { let line=new ChartLine(); line.Canvas=hqChart.Canvas; line.DrawType=1; line.Name=varItem.Name; line.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; line.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; if (varItem.Color) line.Color=varItem.Color; else line.Color=this.GetDefaultColor(id); if (varItem.LineWidth>0) line.LineWidth=varItem.LineWidth; if (varItem.IsShow==false) line.IsShow=false; let titleIndex=windowIndex+1; line.Data.Data=varItem.Data; hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(line.Data,varItem.Name,line.Color); hqChart.ChartPaint.push(line); } this.CreateColorStock=function(hqChart,windowIndex,varItem,id) { let chart=new ChartMACD(); chart.Canvas=hqChart.Canvas; chart.Name=varItem.Name; chart.ChartBorder=hqChart.Frame.SubFrame[windowIndex].Frame.ChartBorder; chart.ChartFrame=hqChart.Frame.SubFrame[windowIndex].Frame; let titleIndex=windowIndex+1; chart.Data.Data=varItem.Data; hqChart.TitlePaint[titleIndex].Data[id]=new DynamicTitleData(chart.Data,varItem.Name,this.GetDefaultColor(id)); hqChart.ChartPaint.push(chart); } //给一个默认的颜色 this.GetDefaultColor=function(id) { let COLOR_ARRAY= [ "rgb(255,174,0)", "rgb(25,199,255)", "rgb(175,95,162)", "rgb(236,105,65)", "rgb(68,114,196)", "rgb(229,0,79)", "rgb(0,128,255)", "rgb(252,96,154)", "rgb(42,230,215)", "rgb(24,71,178)", ]; let number=parseInt(id); return COLOR_ARRAY[number%(COLOR_ARRAY.length-1)]; } } /* json格式数据指标 用来显示本地数据 */ function JsonDataIndex(name,script,args,option) { this.newMethod=PyScriptIndex; //派生 this.newMethod(name); delete this.newMethod; this.JsonData; //json格式数据 if (option.JsonData) this.JsonData=option.JsonData; this.RequestData=function(hqChart,windowIndex,hisData) { if (!this.JsonData) { console.warn("[PyScriptIndex::RequestData] JsonData is null"); if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback('json 数据不能为空'); } else { var param= { HQChart:hqChart, WindowIndex:windowIndex, HistoryData:hisData }; this.JsonData.code=0; var recvData=this.JsonData; this.RecvData(recvData,param); } } } //给一个默认的颜色 PyScriptIndex.prototype.GetDefaultColor=function(id) { let COLOR_ARRAY= [ "rgb(255,174,0)", "rgb(25,199,255)", "rgb(175,95,162)", "rgb(236,105,65)", "rgb(68,114,196)", "rgb(229,0,79)", "rgb(0,128,255)", "rgb(252,96,154)", "rgb(42,230,215)", "rgb(24,71,178)", ]; let number=parseInt(id); return COLOR_ARRAY[number%(COLOR_ARRAY.length-1)]; } /* 点位研判函数 HJ_1:=REF(LOW,1); HJ_2:=SMA(ABS(LOW-HJ_1),13,1)/SMA(MAX(LOW-HJ_1,0),13,1)*100; HJ_3:=EMA(IF(CLOSE*1.2,HJ_2*13,HJ_2/13),13); HJ_4:=LLV(LOW,34); HJ_5:=HHV(HJ_3,34); HJ_6:=IF(LLV(LOW,56),1,0); HJ_7:=EMA(IF(LOW<=HJ_4,(HJ_3+HJ_5*2)/2,0),3)/618*HJ_6; HJ_8:=HJ_7>REF(HJ_7,1); HJ_9:=REF(LLV(LOW,100),3); HJ_10:=REFDATE(HJ_9,DATE); HJ_11:=LOW=HJ_10; HJ_12:=HJ_8 AND HJ_11; HJ_13:=HJ_12>REF(HJ_12,1); 启动买点:HJ_13>REF(HJ_13,1),COLORRED,LINETHICK1; */ function LighterIndex3() { this.newMethod=BaseIndex; //派生 this.newMethod('点位研判函数'); delete this.newMethod; this.Index=new Array( new IndexInfo("启动买点",null) ); this.Index[0].LineColor='rgb(255,0,0)'; this.BindData=function(hqChart,windowIndex,hisData) { var paint=hqChart.GetChartPaint(windowIndex); if (paint.length!=this.Index.length) return false; var closeData=hisData.GetClose(); var highData=hisData.GetHigh(); var lowData=hisData.GetLow(); //HJ_1:=REF(LOW,1); var hj_1=HQIndexFormula.REF(lowData,1); //HJ_2:=SMA(ABS(LOW-HJ_1),13,1)/SMA(MAX(LOW-HJ_1,0),13,1)*100; var hj_2=HQIndexFormula.ARRAY_MULTIPLY( HQIndexFormula.ARRAY_DIVIDE( HQIndexFormula.SMA(HQIndexFormula.ABS(HQIndexFormula.ARRAY_SUBTRACT(lowData,hj_1)),13,1), HQIndexFormula.SMA(HQIndexFormula.MAX(HQIndexFormula.ARRAY_SUBTRACT(lowData,hj_1),0),13,1) ), 100 ); //HJ_3:=EMA(IF(CLOSE*1.2,HJ_2*13,HJ_2/13),13); var hj_3=HQIndexFormula.EMA( HQIndexFormula.ARRAY_IF(HQIndexFormula.ARRAY_MULTIPLY(closeData,1.2),HQIndexFormula.ARRAY_MULTIPLY(hj_2,13),HQIndexFormula.ARRAY_DIVIDE(hj_2,13)), 13 ); //HJ_4:=LLV(LOW,34); var hj_4=HQIndexFormula.LLV(lowData,34); //HJ_5:=HHV(HJ_3,34); var hj_5=HQIndexFormula.HHV(hj_3,34); //HJ_6:=IF(LLV(LOW,56),1,0); var hj_6=HQIndexFormula.ARRAY_IF(HQIndexFormula.LLV(lowData,56),1,0); //HJ_7:=EMA(IF(LOW<=HJ_4,(HJ_3+HJ_5*2)/2,0),3)/618*HJ_6; //hj_7_temp=(HJ_3+HJ_5*2)/2,0) 太长了 这部分单独算下 var hj_7_temp=HQIndexFormula.ARRAY_DIVIDE(HQIndexFormula.ARRAY_ADD(hj_3,HQIndexFormula.ARRAY_MULTIPLY(hj_5,2)),2); var hj_7=HQIndexFormula.ARRAY_MULTIPLY( HQIndexFormula.ARRAY_DIVIDE( HQIndexFormula.EMA( HQIndexFormula.ARRAY_IF(HQIndexFormula.ARRAY_LTE(lowData,hj_4),hj_7_temp,0), 3 ), 618 ), hj_6 ); //HJ_8:=HJ_7>REF(HJ_7,1); var hj_8=HQIndexFormula.ARRAY_GT(hj_7,HQIndexFormula.REF(hj_7,1)); //HJ_9:=REF(LLV(LOW,100),3); var hj_9=HQIndexFormula.REF(HQIndexFormula.LLV(lowData,100),3); //HJ_10:=REFDATE(HJ_9,DATE); 用当日的数据 产生数组 var hj_10=HQIndexFormula.REFDATE(hj_9,-1); //HJ_11:=LOW=HJ_10; var hj_11=HQIndexFormula.ARRAY_EQ(lowData,hj_10); //HJ_12:=HJ_8 AND HJ_11; var hj_12=HQIndexFormula.ARRAY_AND(hj_8,hj_11); var buyData=null; paint[0].Data.Data=hj_12; 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); } hqChart.TitlePaint[titleIndex].Title=this.FormatIndexTitle(); return true; } } /* 信息地雷 */ /* 信息地雷列表 */ function JSKLineInfoMap() { } JSKLineInfoMap.Get=function(id) { var infoMap=new Map( [ ["互动易", {Create:function(){ return new InvestorInfo()} }], ["公告", {Create:function(){ return new AnnouncementInfo()} }], ["业绩预告", {Create:function(){ return new PforecastInfo()} }], ["调研", {Create:function(){ return new ResearchInfo()} }], ["大宗交易", {Create:function(){ return new BlockTrading()} }], ["龙虎榜", {Create:function(){ return new TradeDetail()} }] ] ); return infoMap.get(id); } JSKLineInfoMap.GetClassInfo=function(id) { var infoMap=new Map( [ ["互动易", { ClassName:"InvestorInfo" }], ["公告", { ClassName:"AnnouncementInfo" }], ["业绩预告", { ClassName:"PforecastInfo" } ], ["调研", { ClassName:"ResearchInfo" }], ["大宗交易", { ClassName:"BlockTrading" }], ["龙虎榜", { ClassName:"TradeDetail"} ] ] ); return infoMap.get(id); } JSKLineInfoMap.GetIconUrl=function(type) { switch(type) { case KLINE_INFO_TYPE.INVESTOR: return g_JSChartResource.KLine.Info.Investor.Icon; break; case KLINE_INFO_TYPE.PFORECAST: return g_JSChartResource.KLine.Info.Pforecast.Icon; case KLINE_INFO_TYPE.ANNOUNCEMENT: return g_JSChartResource.KLine.Info.Announcement.Icon; case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_1: case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_2: case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_3: case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_4: return g_JSChartResource.KLine.Info.Announcement.IconQuarter; case KLINE_INFO_TYPE.RESEARCH: return g_JSChartResource.KLine.Info.Research.Icon; case KLINE_INFO_TYPE.BLOCKTRADING: return g_JSChartResource.KLine.Info.BlockTrading.Icon; case KLINE_INFO_TYPE.TRADEDETAIL: return g_JSChartResource.KLine.Info.TradeDetail.Icon; default: return g_JSChartResource.KLine.Info.Announcement.Icon; } } JSKLineInfoMap.GetIconFont=function(type) { switch(type) { case KLINE_INFO_TYPE.INVESTOR: return g_JSChartResource.KLine.Info.Investor.IconFont; break; case KLINE_INFO_TYPE.PFORECAST: return g_JSChartResource.KLine.Info.Pforecast.IconFont; case KLINE_INFO_TYPE.ANNOUNCEMENT: return g_JSChartResource.KLine.Info.Announcement.IconFont; case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_1: case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_2: case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_3: case KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_4: return g_JSChartResource.KLine.Info.Announcement.IconFont2; case KLINE_INFO_TYPE.RESEARCH: return g_JSChartResource.KLine.Info.Research.IconFont; case KLINE_INFO_TYPE.BLOCKTRADING: return g_JSChartResource.KLine.Info.BlockTrading.IconFont; case KLINE_INFO_TYPE.TRADEDETAIL: return g_JSChartResource.KLine.Info.TradeDetail.IconFont; default: return g_JSChartResource.KLine.Info.Announcement.IconFont; } } function IKLineInfo() { this.MaxReqeustDataCount=1000; this.StartDate=20160101; this.Data; this.ClassName='IKLineInfo'; this.GetToday=function() { var date=new Date(); var today=date.getFullYear()*10000+(date.getMonth()+1)*100+date.getDate(); return today; } } //互动易 function InvestorInfo() { this.newMethod=IKLineInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='InvestorInfo'; this.RequestData=function(hqChart) { var self = this; var param= { HQChart:hqChart, }; this.Data=[]; //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.KLine.Info.Investor.ApiUrl, data: { "filed": ["question","answerdate","symbol","id"], "symbol": [param.HQChart.Symbol], "querydate":{"StartDate":this.StartDate,"EndDate":this.GetToday()}, "start":0, "end":this.MaxReqeustDataCount, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.list.length<=0) return; for(var i in recvData.list) { var item=recvData.list[i]; var infoData=new KLineInfoData(); infoData.Date=item.answerdate; infoData.Title=item.question; infoData.InfoType=KLINE_INFO_TYPE.INVESTOR; this.Data.push(infoData); } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } } //公告 function AnnouncementInfo() { this.newMethod=IKLineInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='AnnouncementInfo'; this.ApiType=1; //0=读API 1=读OSS缓存文件 this.RequestData=function(hqChart) { var self = this; var param= { HQChart:hqChart, }; this.Data=[]; if (this.ApiType==1) //取缓存文件 { var url=`${g_JSChartResource.CacheDomain}/cache/analyze/shszreportlist/${param.HQChart.Symbol}.json`; JSNetwork.HttpRequest({ url: url, type:"get", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); }, error: function(http,e) { self.RecvError(http,e,param);; } }); } else //取api { //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.KLine.Info.Announcement.ApiUrl, data: { "filed": ["title","releasedate","symbol","id"], "symbol": [param.HQChart.Symbol], "querydate":{"StartDate":this.StartDate,"EndDate":this.GetToday()}, "start":0, "end":this.MaxReqeustDataCount, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); }, error: function(http,e) { self.RecvError(http,e,param);; } }); } } this.RecvData=function(recvData,param) { if (recvData.report.length<=0) return; for(var i in recvData.report) { var item=recvData.report[i]; var infoData=new KLineInfoData(); infoData.Date=item.releasedate; infoData.Title=item.title; infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT; for(var j in item.type) { var typeItem=item.type[j]; switch(typeItem) { case "一季度报告": infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_1; break; case "半年度报告": infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_2; break; case "三季度报告": infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_3; break; case "年度报告": infoData.InfoType=KLINE_INFO_TYPE.ANNOUNCEMENT_QUARTER_4; break; } } this.Data.push(infoData); } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } this.RecvError=function(http,e,param) { console.warn("[AnnouncementInfo::RecvError] error, http ",e, http); //if (param.HQChart.ScriptErrorCallback) param.HQChart.ScriptErrorCallback(e); } } //业绩预告 function PforecastInfo() { this.newMethod=IKLineInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='PforecastInfo'; this.RequestData=function(hqChart) { var self = this; var param= { HQChart:hqChart, }; this.Data=[]; //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.KLine.Info.Pforecast.ApiUrl, data: { "field": ["pforecast.type","pforecast.reportdate","fweek"], "condition": [ {"item":["pforecast.reportdate","int32","gte",this.StartDate]} ], "symbol": [param.HQChart.Symbol], "start":0, "end":this.MaxReqeustDataCount, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.stock.length!=1) return; if (recvData.stock[0].stockday.length<=0) return; for(var i in recvData.stock[0].stockday) { var item=recvData.stock[0].stockday[i]; if (item.pforecast.length>0) { var dataItem=item.pforecast[0]; var infoData=new KLineInfoData(); infoData.Date= item.date; infoData.Title=dataItem.type; infoData.InfoType=KLINE_INFO_TYPE.PFORECAST; infoData.ExtendData={ Type:dataItem.type, ReportDate:dataItem.reportdate} if(item.fweek) //未来周涨幅 { infoData.ExtendData.FWeek={}; if (item.fweek.week1!=null) infoData.ExtendData.FWeek.Week1=item.fweek.week1; if (item.fweek.week4!=null) infoData.ExtendData.FWeek.Week4=item.fweek.week4; } this.Data.push(infoData); } } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } } //投资者关系 (调研) function ResearchInfo() { this.newMethod=IKLineInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='ResearchInfo'; this.RequestData=function(hqChart) { var self = this; var param= { HQChart:hqChart }; this.Data=[]; //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.KLine.Info.Research.ApiUrl, data: { "filed": ["releasedate","researchdate","level","symbol","id",'type'], "querydate":{"StartDate":this.StartDate,"EndDate":this.GetToday()}, "symbol": [param.HQChart.Symbol], "start":0, "end":this.MaxReqeustDataCount, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.list.length<=0) return; for(var i in recvData.list) { var item=recvData.list[i]; var infoData=new KLineInfoData(); infoData.ID=item.id; infoData.Date= item.researchdate; infoData.InfoType=KLINE_INFO_TYPE.RESEARCH; infoData.ExtendData={ Level:item.level , Type:item.type}; this.Data.push(infoData); } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } } //大宗交易 function BlockTrading() { this.newMethod=IKLineInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='BlockTrading'; this.RequestData=function(hqChart) { var self = this; var param= { HQChart:hqChart }; this.Data=[]; //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.KLine.Info.BlockTrading.ApiUrl, data: { "field": ["blocktrading.price","blocktrading.vol","blocktrading.premium","fweek","price"], "condition": [ {"item":["date","int32","gte",this.StartDate]}, {"item":["blocktrading.vol","int32","gte","0"]} ], "symbol": [param.HQChart.Symbol], "start":0, "end":this.MaxReqeustDataCount, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.stock.length!=1) return; if (recvData.stock[0].stockday.length<=0) return; for(var i in recvData.stock[0].stockday) { var item=recvData.stock[0].stockday[i]; var infoData=new KLineInfoData(); infoData.Date= item.date; infoData.InfoType=KLINE_INFO_TYPE.BLOCKTRADING; infoData.ExtendData= { Price:item.blocktrading.price, //交易价格 Premium:item.blocktrading.premium, //溢价 (百分比%) Vol:item.blocktrading.vol, //交易金额单位(万元) ClosePrice:item.price, //收盘价 }; if(item.fweek) //未来周涨幅 { infoData.ExtendData.FWeek={}; if (item.fweek.week1!=null) infoData.ExtendData.FWeek.Week1=item.fweek.week1; if (item.fweek.week4!=null) infoData.ExtendData.FWeek.Week4=item.fweek.week4; } this.Data.push(infoData); } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } } //龙虎榜 function TradeDetail() { this.newMethod=IKLineInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='TradeDetail'; this.RequestData=function(hqChart) { var self = this; var param= { HQChart:hqChart }; this.Data=[]; //请求数据 JSNetwork.HttpRequest({ url: g_JSChartResource.KLine.Info.TradeDetail.ApiUrl, data: { "field": ["tradedetail.typeexplain","tradedetail.type","fweek"], "condition": [ {"item":["date","int32","gte",this.StartDate]}, {"item":["tradedetail.type","int32","gte","0"]} ], "symbol": [param.HQChart.Symbol], "start":0, "end":this.MaxReqeustDataCount, }, type:"post", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); } }); return true; } this.RecvData=function(recvData,param) { if (recvData.stock.length!=1) return; if (recvData.stock[0].stockday.length<=0) return; for(var i in recvData.stock[0].stockday) { var item=recvData.stock[0].stockday[i]; var infoData=new KLineInfoData(); infoData.Date= item.date; infoData.InfoType=KLINE_INFO_TYPE.TRADEDETAIL; infoData.ExtendData={Detail:new Array()}; for(var j in item.tradedetail) { var tradeItem=item.tradedetail[j]; infoData.ExtendData.Detail.push({"Type":tradeItem.type,"TypeExplain":tradeItem.typeexplain}); } if(item.fweek) //未来周涨幅 { infoData.ExtendData.FWeek={}; if (item.fweek.week1!=null) infoData.ExtendData.FWeek.Week1=item.fweek.week1; if (item.fweek.week4!=null) infoData.ExtendData.FWeek.Week4=item.fweek.week4; } this.Data.push(infoData); } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } } function JSMinuteInfoMap() { } JSMinuteInfoMap.InfoMap=new Map( [ ["大盘异动", {Create:function(){ return new MarketEventInfo()} }], ]); JSMinuteInfoMap.Get=function(id) { return JSMinuteInfoMap.InfoMap.get(id); } function IMinuteInfo() { this.Data; this.ClassName='IMinuteInfo'; } ////////////////////////////////////////////////////////////////////// // 大盘异动 // 结构 {Date:日期 Time:时间, Title:标题, Type:0 } //////////////////////////////////////////////////////////////////// function MarketEventInfo() { this.newMethod=IMinuteInfo; //派生 this.newMethod(); delete this.newMethod; this.ClassName='MarketEventInfo'; this.RequestData=function(hqChart) { var self = this; this.Data=[]; var param= { HQChart:hqChart }; var url=g_JSChartResource.CacheDomain+'/cache/analyze/shszevent/marketevent/concept/'+hqChart.TradeDate+'.json'; if (hqChart.NetworkFilter) { var obj= { Name:'MarketEventInfo::RequestData', //类名:: Explain:'大盘异动', Request:{ Url:url, Type:'Get', Data: { Date:hqChart.TradeDate, Symbol:hqChart.Symbol } }, Self:this, PreventDefault:false }; hqChart.NetworkFilter(obj, function(data) { self.RecvData(data,param); param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } //请求数据 JSNetwork.HttpRequest({ url: url, type:"get", dataType: "json", async:true, success: function (recvData) { self.RecvData(recvData,param); }, error: function(http,e) { console.warn("[MarketEventInfo::RequestData] error, http ",e, http); } }); return true; } this.RecvData=function(recvData,param) { for(var i in recvData.event) { var event=recvData.event[i]; for(var j in event.data) { var item=event.data[j]; if (item.length<2) continue; var info={Date:event.date, Time:item[0], Title:item[1], Type:0}; this.Data.push(info); } } param.HQChart.UpdataChartInfo(); param.HQChart.Draw(); } } //注意!!! 这个函数已经不用了 //是否是指数代码 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; } //注意!!! 这个函数已经不用了 //是否是基金代码 function IsFundSymbol(symbol) { if (!symbol) return false; var upperSymbol=symbol.toUpperCase(); if (upperSymbol.indexOf('.SH')>0) { upperSymbol=upperSymbol.replace('.SH',''); //51XXXX.sh if (upperSymbol.charAt(0)=='5' && upperSymbol.charAt(1)=='1') return true; } else if (upperSymbol.indexOf('.SZ')>0) { upperSymbol=upperSymbol.replace('.SZ',''); //15XXXX.sz, 16XXXX.sz, 17XXXX.sz, 18XXXX.sz if (upperSymbol.charAt(0)=='1' && (upperSymbol.charAt(1)=='5' || upperSymbol.charAt(1)=='6' || upperSymbol.charAt(1)=='7' || upperSymbol.charAt(1)=='8') ) return true; } return false; } //设置窗口基类 function IDivDialog(divElement) { this.DivElement=divElement; //父节点 this.ID=null; //div id this.TimeOut=null; //定时器 //隐藏窗口 this.Hide=function() { $("#"+this.ID).hide(); } //显示窗口 this.Show=function(left,top,width,height) { //显示位置 $("#"+this.ID).css({'display':'block','top':top+'px', "left":left+'px', "width":width+'px', "height":height+'px' }); } } //修改指标 function ModifyIndexDialog(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.Title={ ID:Guid() }; //标题 this.ParamList={ID:Guid() }; //参数列表 class='parameter-content' this.ParamData=[]; //{ ID:参数ID, Value:参数值} this.Identify; this.HQChart; //创建 this.Create=function() { this.ID=Guid(); var div=document.createElement('div'); div.className='jchart-modifyindex-box'; div.id=this.ID; div.innerHTML= "
\
\ \ \
\
MA
\ \
"; this.DivElement.appendChild(div); //确定按钮 $("#"+this.ID+" .submit").click( { divBox:this, }, function(event) { event.data.divBox.Hide(); }); //给一个id 后面查找方便 var titleElement=div.getElementsByTagName('span')[0]; titleElement.id=this.Title.ID; var paramListElement=div.getElementsByClassName('parameter-content')[0]; paramListElement.id=this.ParamList.ID; } //设置标题 this.SetTitle=function(title) { $("#"+this.Title.ID).html(title); } //清空参数 this.ClearParamList=function() { $("#"+this.ParamList.ID).empty(); this.ParamData=[]; } this.BindParam=function(chart,identify) { var windowIndex=chart.WindowIndex[identify]; for(var i in windowIndex.Arguments) { var item=windowIndex.Arguments[i]; if (item.Name==null || isNaN(item.Value)) break; var guid=Guid(); var param = ''+ item.Name +'
'; $("#"+this.ParamList.ID).append(param); this.ParamData.push({ID:guid,Value:item.Value}); } //绑定参数修改事件 var self=this; for(var i in this.ParamData) { var item=this.ParamData[i]; $("#"+item.ID).mouseup( { Chart:chart, Identify:identify, ParamIndex:i //参数序号 }, function(event) { var value = parseInt($(this).val()); //获取当前操作的input属性值,转化为整型 var chart=self.HQChart; var identify=self.Identify; var paramIndex=event.data.ParamIndex; chart.WindowIndex[identify].Arguments[paramIndex].Value = value; //为参数属性重新赋值 chart.UpdateWindowIndex(identify); //调用更新窗口指标函数,参数用来定位窗口 } ) $("#"+item.ID).keyup( { Chart:chart, Identify:identify, ParamIndex:i //参数序号 }, function(event) { var value = parseInt($(this).val()); //获取当前操作的input属性值,转化为整型 var chart=self.HQChart; var identify=self.Identify; var paramIndex=event.data.ParamIndex; chart.WindowIndex[identify].Arguments[paramIndex].Value = value; //为参数属性重新赋值 chart.UpdateWindowIndex(identify); //调用更新窗口指标函数,参数用来定位窗口 } ) } } //绑定取消事件 this.BindCancel=function() { //取消按钮事件 var self=this; $("#"+this.ID+" .cancel").click( function() { var chart=self.HQChart; var identify=self.Identify; self.RestoreParam(chart.WindowIndex[identify]); chart.UpdateWindowIndex(identify); self.Hide(); } ); //关闭和取消是一样的 $("#"+this.ID+" #close").click( function() { var chart=self.HQChart; var identify=self.Identify; self.RestoreParam(chart.WindowIndex[identify]); chart.UpdateWindowIndex(identify); self.Hide(); } ); } //还原参数 this.RestoreParam=function(windowIndex) { for(var i in this.ParamData) { var item=this.ParamData[i]; windowIndex.Arguments[i].Value=item.Value; } } //显示 this.DoModal=function(event) { var chart=event.data.Chart; var identify=event.data.Identify; var dialog=chart.ModifyIndexDialog; if(!dialog) return; if (dialog.ID==null) dialog.Create(); //第1次 需要创建div dialog.Identify=identify; dialog.HQChart=chart; dialog.SetTitle(chart.WindowIndex[identify].Name+" 指标参数设置"); //设置标题 dialog.ClearParamList(); //清空参数 dialog.BindParam(chart,identify); //绑定参数 dialog.BindCancel(); //绑定取消和关闭事件 //居中显示 var border=chart.Frame.ChartBorder; var scrollPos=GetScrollPosition(); var left=border.GetLeft()+border.GetWidth()/2; var top=border.GetTop()+border.GetHeight()/2; //left = left + border.UIElement.getBoundingClientRect().left+scrollPos.Left; //top = top+ border.UIElement.getBoundingClientRect().top+scrollPos.Top; dialog.Show(left,top,200,200); //显示 } } //换指标 function ChangeIndexDialog(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.DivElement=divElement; //父节点 this.IndexTreeApiUrl="https://opensourcecache.zealink.com/cache/hqh5/index/commonindextree.json"; //数据下载地址 this.OverlayIndexTreeApiUrl="https://opensourcecache.zealink.com/cache/hqh5/index/commonindextree.json"; //叠加指标列表数据下载地址 this.IsOverlayIndex=false; this.Create=function() { var div=document.createElement('div'); div.className='jchart-changeindex-box'; div.id=this.ID=Guid(); div.innerHTML= '
\n' + '
\n' + ' 换指标\n' + ' \n' + '
\n' + '
\n' + '
\n' + ' \n' + '
    \n' + '
    \n' + '
    \n' + '
      \n' + '
      \n' + '
      \n' + '
      '; this.DivElement.appendChild(div); } //下载数据 如果上次下载过可以 可以不用下载 this.ReqeustData=function() { if($(".target-left ul li").length>0){ return false; } var url = this.IndexTreeApiUrl; if (this.IsOverlayIndex==true) url=this.OverlayIndexTreeApiUrl; JSNetwork.HttpRequest({ url: url, type: 'get', success: function (res) { var item = res.list; changeIndexLeftList(item); //处理左侧list列表 changeIndexRightList(item); //处理右侧内容列表 } }); //处理左侧list列表 function changeIndexLeftList(item) { $.each(item,function(i,result){ var htmlList; htmlList = '
    • ' + result.node + '
    • '; $(".target-left ul").append(htmlList); }); //默认选中第一项 $(".target-left ul li:first-child").addClass("active-list"); } //处理右侧内容列表 function changeIndexRightList(listNum) { var contentHtml; var conData = []; $.each(listNum,function(index,result){ conData.push(result.list); }) //页面初始化时显示第一个列表分类下的内容 $.each(conData[0],function (i, res) { contentHtml = '
    • '+ res.name +'
    • '; $(".target-right ul").append(contentHtml); }) //切换list $(".target-left ul").delegate("li","click",function () { $(this).addClass("active-list").siblings().removeClass("active-list"); var item = $(this).index(); $(".target-right ul").html(""); $.each(conData[item],function (i, res) { contentHtml = '
    • '+ res.name +'
    • '; $(".target-right ul").append(contentHtml); }) }) } } this.BindClose=function(chart) { //关闭按钮 $("#"+this.ID+" .close-tar").click( { Chart:chart, }, function(event) { var chart=event.data.Chart; chart.ChangeIndexDialog.Hide(); } ); } //搜索事件 this.BindSearch=function(chart) { $(".target-left input").on('input', { Chart:chart }, function(event) { let scriptData = new JSIndexScript(); let result=scriptData.Search(event.target.value); $(".target-right ul").html(""); for(var i in result) { var name=result[i]; var contentHtml = '
    • '+ name +'
    • '; $(".target-right ul").append(contentHtml); } } ); } this.DoModal=function(event) { var chart=event.data.Chart; var identify=event.data.Identify; var dialog=chart.ChangeIndexDialog; var isOverlay=event.data.IsOverlay; //是否叠加 if(!dialog) return; if (dialog.ID==null) dialog.Create(); //第1次 需要创建div dialog.IsOverlayIndex=isOverlay; dialog.ReqeustData(); //下载数据 //切换窗口指标类型 每次委托事件执行之前,先用undelegate()解除之前的所有绑定 changeIndeWindow(); function changeIndeWindow() { $(".target-right ul").undelegate().delegate("li","click",function () { var idv = $(this).attr("id"); if (isOverlay) chart.AddOverlayIndex({WindowIndex:identify,IndexName:idv}); else chart.ChangeIndex(identify,idv); $(this).addClass("active-list").siblings().removeClass("active-list"); }); } dialog.BindSearch(chart); //关闭弹窗 dialog.BindClose(chart); //居中显示 var border=chart.Frame.ChartBorder; var scrollPos=GetScrollPosition(); var left=border.GetLeft()+border.GetWidth()/2; var top=border.GetTop()+border.GetHeight()/2; //left = left + border.UIElement.getBoundingClientRect().left+scrollPos.Left; //top = top+ border.UIElement.getBoundingClientRect().top+scrollPos.Top; dialog.Show(left,top,200,200); } } //信息地理tooltip function KLineInfoTooltip(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.UpColor=g_JSChartResource.UpTextColor; this.DownColor=g_JSChartResource.DownTextColor; this.UnchagneColor=g_JSChartResource.UnchagneTextColor; this.Create=function() { this.ID=Guid(); var div=document.createElement('div'); div.className='jchart-klineinfo-tooltip'; div.id=this.ID; div.innerHTML="
      "; this.DivElement.appendChild(div); } this.BindInfoList=function(infoType,infoList) { var strBox="
      共"+infoList.length+"条
      "; var strText=[]; for(var i in infoList) { var item=infoList[i]; var strOld=item.Date; if(infoType==KLINE_INFO_TYPE.PFORECAST) { var reportDate=item.ExtendData.ReportDate; var year=parseInt(reportDate/10000); //年份 var day=reportDate%10000; //比较 这个去掉年份的日期 var reportType; if(day == 1231){ reportType = "年报" }else if(day == 331){ reportType = "一季度报" }else if(day == 630){ reportType = "半年度报" }else if(day == 930){ reportType = "三季度报" } var weekData=""; if (item.ExtendData.FWeek) { if (item.ExtendData.FWeek.Week1!=null) weekData+="一周后涨幅:"+ item.ExtendData.FWeek.Week1.toFixed(2)+"%"; if (item.ExtendData.FWeek.Week4!=null) weekData+=" 四周后涨幅:"+ item.ExtendData.FWeek.Week4.toFixed(2)+"%"; if (weekData.length>0) weekData="
        "+weekData+""; } var strDate=item.Date.toString(); var strNew=strDate.substring(0,4)+"-"+strDate.substring(4,6)+"-"+strDate.substring(6,8); //转换时间格式 strText+=""+strNew+"  "+year+reportType+item.Title+" "+weekData+""; } else if (infoType==KLINE_INFO_TYPE.RESEARCH) //调研单独处理 { var levels=item.ExtendData.Level; var recPerson=[]; if(levels.length==0){ recPerson = "" }else{ for(var j in levels) { if(levels[j]==0){ recPerson+="证券代表   "; }else if(levels[j]==1){ recPerson+="董秘   "; }else if(levels[j]==2){ recPerson+="总经理   "; }else if(levels[j]==3){ recPerson+="董事长   "; } } } var strDate=item.Date.toString(); var strNew=strDate.substring(0,4)+"-"+strDate.substring(4,6)+"-"+strDate.substring(6,8); //转换时间格式 strText+=""+strNew+"   接待:   "+recPerson+""; }else if(infoType==KLINE_INFO_TYPE.BLOCKTRADING) { var showPriceInfo = item.ExtendData; var strDate=item.Date.toString(); var strNew=strDate.substring(0,4)+"-"+strDate.substring(4,6)+"-"+strDate.substring(6,8); //转换时间格式 strText+=""+strNew+"  成交价: "+showPriceInfo.Price.toFixed(2)+"收盘价: "+showPriceInfo.ClosePrice.toFixed(2)+ "
      溢折价率: "+ showPriceInfo.Premium.toFixed(2)+"%成交量(万股): "+showPriceInfo.Vol.toFixed(2)+"
      "; } else if (infoType==KLINE_INFO_TYPE.TRADEDETAIL) //龙虎榜 { /*var detail=[ "日价格涨幅偏离值达到9.89%", "日价格涨幅偏离值达格涨幅偏离值达格涨幅偏离值达到9.89%" ]*/ var detail=item.ExtendData.Detail; //格式:日期 上榜原因: detail[0].TypeExplain // detail[1].TypeExplain // 一周后涨幅: xx 四周后涨幅: xx var str=strOld.toString(); var strNew=str.substring(0,4)+"-"+str.substring(4,6)+"-"+str.substring(6,8); //转换时间格式 var reasons = []; for(var i in detail){ reasons += ""+detail[i].TypeExplain+"
      " // reasons += detail[i] + "
      " } strText = ""+strNew+"   上榜原因:  "+reasons+"
      一周后涨幅: "+ item.ExtendData.FWeek.Week1.toFixed(2)+ "%   四周后涨幅: "+ item.ExtendData.FWeek.Week4.toFixed(2)+"%
      "; } else { var str=strOld.toString(); var strNew=str.substring(0,4)+"-"+str.substring(4,6)+"-"+str.substring(6,8); //转换时间格式 strText+=""+strNew+"   "+item.Title+""; } } var titleInnerBox = $(".title-length").html(strText); $("#"+this.ID).html(titleInnerBox); //当信息超过8条时,添加“共XX条”统计总数 if(infoList.length > 8){ $("#"+this.ID).append(strBox); } } this.GetColor=function(price) { if(price>0) return this.UpColor; else if (price<0) return this.DownColor; else return this.UnchagneColor; } //显示窗口,改函数仅为KLineInfoTooltip使用 this.Show=function(left,top,width,height,tooltip,times) { //显示位置 $("#"+this.ID).css({'display':'block','top':top+'px', "left":left+'px', "width":width+'px', "height":height+'px' }); function toolHide() { tooltip.Hide(); } if (this.TimeOut!=null) clearTimeout(this.TimeOut); //清空上一次的定时器,防止定时器不停的被调用 //设置窗口定时隐藏 this.TimeOut=setTimeout(toolHide,times); } this.DoModal=function(event) { var chart=event.data.Chart; var infoType=event.data.InfoType; //信息地雷类型 var infoList=event.data.InfoList; //信息数据列表 var tooltip=chart.KLineInfoTooltip; if(!tooltip) return; if (tooltip.ID==null) tooltip.Create(); //第1次 需要创建div tooltip.BindInfoList(infoType,infoList); var left=event.pageX; var top=event.pageY+10; var widthTool=380; var heightTool=$("#"+tooltip.ID).height(); if((left + widthTool) > chart.UIElement.getBoundingClientRect().width){ left = left - widthTool; } /*if(top+heightTool>chart.UIElement.getBoundingClientRect().height){ top=top-heightTool-45; }*/ tooltip.Show(left,top,widthTool,"auto",tooltip,8000); } //鼠标离开 this.Leave=function(event) { var chart=event.data.Chart; var tooltip=chart.KLineInfoTooltip; if(!tooltip || tooltip.ID==null) return; tooltip.Hide(); } } //历史K线上双击 弹出分钟走势图框 function MinuteDialog(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.JSChart=null; this.Height=500; this.Width=600; this.Symbol; this.TradeDate; this.HistoryData; this.Create=function() { this.ID=Guid(); var div=document.createElement('div'); div.className='jchart-kline-minute-box'; div.id=this.ID; var hqchartID=Guid(); div.innerHTML=`
      `; div.style.width=this.Height+'px'; div.style.height=this.Width+'px'; this.DivElement.appendChild(div); this.JSChart=JSChart.Init(document.getElementById(hqchartID)); var option= { Type:'历史分钟走势图', Symbol:this.Symbol, //股票代码 IsAutoUpdate:false, //是自动更新数据 IsShowRightMenu:false, //右键菜单 HistoryMinute: { TradeDate:this.TradeDate, IsShowName:false, IsShowDate:false } //显示的交易日期 }; this.JSChart.SetOption(option); } this.BindClose=function(chart) { //关闭按钮 $("#"+this.ID+" .close-munite").click( { Chart:chart }, function(event) { var chart=event.data.Chart; chart.MinuteDialog.Hide(); } ); } this.DoModal=function(event) { this.UpColor=g_JSChartResource.UpTextColor; this.DownColor=g_JSChartResource.DownTextColor; this.UnchagneColor=g_JSChartResource.UnchagneTextColor; var chart=event.data.Chart; var tooltip=event.data.Tooltip; var dialog=chart.MinuteDialog; dialog.Symbol=chart.Symbol; dialog.TradeDate=tooltip.Data.Date; if(!dialog) return; if (dialog.ID==null) { dialog.Create(); //第1次 需要创建div } else { dialog.JSChart.JSChartContainer.TradeDate=dialog.TradeDate; dialog.JSChart.ChangeSymbol(this.Symbol); } var left=event.clientX; var top=event.clientY+10; dialog.Show(500,100,600,500); dialog.JSChart.OnSize(); this.BindClose(chart); this.GetColor=function(price,yclse) { if(price>yclse) return this.UpColor; else if (price"+""+strNewDate+" "+ "开:"+strData.Open.toFixed(2)+""+ "高:"+strData.High.toFixed(2)+""+ "低:"+strData.Low.toFixed(2)+""+ "收:"+strData.Close.toFixed(2)+""+ "量:"+IFrameSplitOperator.FormatValueString(strData.Vol,2)+""+ "额:"+IFrameSplitOperator.FormatValueString(strData.Amount,2)+""; $(".minute-dialog-title span").html(str); } } //区间统计 function KLineSelectRectDialog(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.SelectData; this.Dialog; this.HQChart; //隐藏窗口 this.Close=function() { if (this.Dialog) { this.DivElement.removeChild(this.Dialog); this.Dialog=null; } this.HQChart.HideSelectRect(); } //创建 this.Create=function() { this.ID=Guid(); var div=document.createElement('div'); div.className='jchart-select-statistics-box'; div.id=this.ID; div.innerHTML= "
      \
      \ 区间统计\ \
      \
      统计数据
      \ \
      "; this.DivElement.appendChild(div); this.Dialog=div; //关闭按钮 $("#"+this.ID+" #close").click( { divBox:this, }, function(event) { event.data.divBox.Close(); }); //形态匹配 $("#"+this.ID+" #match").click( { divBox:this, }, function(event) { event.data.divBox.KLineMatch(); }); } this.BindData=function() { var hqData=this.SelectData.Data; var start=this.SelectData.Start; var end=this.SelectData.End; var showData= { Open:0,Close:0,High:0,Low:0, YClose:0, Vol:0, Amount:0, Date:{Start:0,End:0}, Count:0, KLine:{ Up:0,Down:0,Unchanged:0 } //阳线|阴线|平线 } for(var i=start; i<=end && iitem.Low) showData.Low=item.Low; if (item.Close>item.Open) ++showData.KLine.Up; else if (item.Close0) showData.AvPrice=showData.Amount/showData.Vol; //均价 if (item.YClose>0) { showData.Increase = (showData.Close - showData.YClose) / showData.YClose *100; //涨幅 showData.Amplitude = (showData.High - showData.Low) / showData.YClose * 100; //振幅 } // console.log('[KLineSelectRectDialog::BindData]', showData); var defaultfloatPrecision=GetfloatPrecision(this.SelectData.Symbol); var startDate = showData.Date.Start.toString().substring(0,4) + "/" + showData.Date.Start.toString().substring(4,6) + "/" + showData.Date.Start.toString().substring(6,8); var endDate = showData.Date.End.toString().substring(0,4) + "/" + showData.Date.End.toString().substring(4,6) + "/" + showData.Date.End.toString().substring(6,8); var startLeftClass="",startRightClass="",endLeftClass="",endRightClass=""; if(start<=0) startLeftClass = "BtnBackground"; if(start >= end) { startRightClass = "BtnBackground"; endLeftClass = "BtnBackground"; } if(end >= hqData.Data.length - 1) endRightClass = "BtnBackground"; var div=document.createElement('div'); div.className='jchart-select-table-right'; div.innerHTML= '
      \n' + ' 开始: '+ startDate +'<>\n' + ' 结束: '+ endDate +'<>\n' + ' 总个数: '+ showData.Count +'\n' + '
      \n' + ' \n' + ' ' + ' ' + ' \n' + ' ' + ' ' + ' \n' + ' ' + ' ' + ' \n' + ' ' + ' ' + ' \n' + '
      起始价: '+ showData.YClose.toFixed(defaultfloatPrecision) +'最终价: '+ showData.Close.toFixed(defaultfloatPrecision) +'均价: '+ showData.AvPrice.toFixed(defaultfloatPrecision) +'
      最低价: '+ showData.Low.toFixed(defaultfloatPrecision) +'最高价: '+ showData.High.toFixed(defaultfloatPrecision) +'涨跌幅: '+ showData.Increase.toFixed(2) +'%
      振幅: '+ showData.Amplitude.toFixed(2) +'%成交量: '+ IFrameSplitOperator.FormatValueString(showData.Vol,2) +'股金额: '+ IFrameSplitOperator.FormatValueString(showData.Amount,2) +'元
      阴线: '+ showData.KLine.Up +'阳线: '+ showData.KLine.Down +'平线: '+ showData.KLine.Unchanged +'
      '; $(".parameter-content").html(div); this.BindEvent(); } this.BindEvent = function () { var _self = this; if(_self.SelectData.Start > 0){ $(".jchart-select-date .start-date-left").click(function () { _self.SelectData.Start--; _self.BindData(); _self.HQChart.UpdateSelectRect(_self.SelectData.Start,_self.SelectData.End); }) } if(_self.SelectData.Start < _self.SelectData.End){ $(".jchart-select-date .start-date-right").click(function () { _self.SelectData.Start++; _self.BindData(); _self.HQChart.UpdateSelectRect(_self.SelectData.Start,_self.SelectData.End); }) $(".jchart-select-date .end-date-left").click(function () { _self.SelectData.End--; _self.BindData(); _self.HQChart.UpdateSelectRect(_self.SelectData.Start,_self.SelectData.End); }) } if(_self.SelectData.End < _self.SelectData.Data.Data.length - 1){ $(".jchart-select-date .end-date-right").click(function () { _self.SelectData.End++; _self.BindData(); _self.HQChart.UpdateSelectRect(_self.SelectData.Start,_self.SelectData.End); }) } } //显示 this.DoModal=function(event) { var chart=event.data.Chart; if (this.ID==null) this.Create(); //第1次 需要创建div this.SelectData=event.data.SelectData; this.HQChart=chart; this.BindData(); //居中显示 var border=chart.Frame.ChartBorder; var scrollPos=GetScrollPosition(); var left=border.GetWidth()/2; var top=border.GetHeight()/2; //left = left + border.UIElement.getBoundingClientRect().left+scrollPos.Left; //top = top+ border.UIElement.getBoundingClientRect().top+scrollPos.Top; this.Show(left,top,200,200); //显示 } //形态匹配 this.KLineMatch=function(data) { var waitDialog=new WaitDialog(this.DivElement); waitDialog.DoModal( { data: { Title:'计算中......', Chart:this.HQChart } }); this.Close(); //关闭窗口 var hqChart=this.HQChart; var param= { Scope: { Plate:["CNA.ci"],Minsimilar:0.90 }, WaitDialog:waitDialog } //沪深A股, 相似度>=90% hqChart.RequestKLineMatch(this.SelectData, param); } } //形态选股 function KLineMatchDialog(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.MatchData; //匹配的股票数据 this.Sample; //样本数据 this.Dialog; this.HQChart; this.PageData; //分页数据 //隐藏窗口 this.Close=function() { this.DivElement.removeChild(this.Dialog); } //创建 this.Create=function() { this.ID=Guid(); var div=document.createElement('div'); div.className='jchart-kline-match-box'; div.id=this.ID; div.innerHTML= `
      形态匹配

      股票名称 匹配度 时间段
      `.trim(); this.DivElement.appendChild(div); this.Dialog=div; //关闭按钮 $("#"+this.ID+" #close").click( { divBox:this, }, function(event) { event.data.divBox.Close(); }); } this.BindData=function() { console.log(`[KLineMatchDialog::BindData] 形态源: ${this.Sample.Stock.Name} 区间:${this.Sample.Date.Start} - ${this.Sample.Date.End}`); var count = this.MatchData.length + 1; var pageData = {NewData:{},MetaData:[],PageCount:0,Count:count}; var pageCount = 0; var paginationHtml = ''; $('#'+this.ID+' .dataCount').html('个数:'+count); for(let i = 0; i < count ; i++){ var dataObj = {}; if(i == 0){ dataObj = { Symbol:this.Sample.Stock.Symbol, Name:this.Sample.Stock.Name, Rate:'形态源', Color:'red', Date:`${this.Sample.Date.Start}-${this.Sample.Date.End}` }; }else{ let dataItem = this.MatchData[i - 1]; dataObj = { Symbol:dataItem.Symbol, Name:dataItem.Name, Rate:Number(dataItem.Similar * 100).toFixed(2), Color:'', Date:`${dataItem.Start}-${dataItem.End}` }; } pageData.MetaData.push(dataObj); } if(pageData.Count % 10 == 0){ pageCount = pageData.Count / 10; }else{ pageCount = Math.floor(pageData.Count / 10) + 1; } pageData.PageCount = pageCount; this.PaginationMetaData(pageData); this.PageData = pageData; console.log('[KLineMatchDialog::DoModal pageData]',pageData); this.RenderDom(1); this.PaginationInit('#'+this.ID,pageData.PageCount,this.paginationCallback); // $('#' + this.ID + ' .pagination').html(paginationHtml); } this.RenderDom = function(page){ let currentPageData = this.PageData.NewData[page]; console.log('[KLineMatchDialog::RenderDom currentPageData]',currentPageData); let bodyHtml = ''; for(let i = 0; i < currentPageData.length; i++){ bodyHtml += ` ${currentPageData[i].Name} ${currentPageData[i].Rate} ${currentPageData[i].Date} `.trim(); } $('#'+this.ID + ' .matchTable tbody').html(bodyHtml) } var _this = this; this.paginationCallback = function(page) { _this.RenderDom(page); _this.PaginationInit('#'+_this.ID,_this.PageData.PageCount,_this.paginationCallback); //更新UI } this.PaginationInit = function(id, maxPageNum, callback) { //初始化分页 var spanStr = ""; var currentPageNum = $(id + " .pagination").data("current"); var lastPageNum = 0; var showCountPage = 5; //只显示5个数字项 if (currentPageNum < showCountPage) { //当前页小于预显示页数 if (maxPageNum >= showCountPage) { for (var j = 0; j < showCountPage; j++) { //上 1 2 3 4 5 下 spanStr += (j + 1) != currentPageNum ? "" + (j + 1) + "" : "" + (j + 1) + ""; } } else { for (var j = 0; j < maxPageNum; j++) { //上 1 2 3 4 5 下 spanStr += (j + 1) != currentPageNum ? "" + (j + 1) + "" : "" + (j + 1) + ""; } } } else { //大于5时,最终页数是当前页数加1 lastPageNum = (currentPageNum + 1) > maxPageNum ? currentPageNum : (currentPageNum + 1); for (var i = currentPageNum - 3; i <= lastPageNum; i++) { //含最终项之前的五项 spanStr += i != currentPageNum ? "" + i + "" : "" + i + ""; } } spanStr = "上一页" + spanStr + "下一页"; $(id + " .pagination").html(spanStr); $(id + " .pagination span").bind('click', { "maxpage": maxPageNum, "Callback": callback }, this.PaginationCurrentIndex); // return spanStr; } this.PaginationCurrentIndex = function(event) { //分页切换 var text = $(this).text(); console.log('[::PaginationCurrentIndex text]',text); var currentPageNum = Number($(this).parent().data("current")); var maxPageNum = event.data.maxpage; var callback = event.data.Callback; var flag = 1; if (text === "上一页") { flag = currentPageNum === 1 ? currentPageNum : currentPageNum - 1; } else if (text === "下一页") { flag = currentPageNum === maxPageNum ? currentPageNum : currentPageNum + 1; } else { flag = Number(text); } $(this).parent().data("current", flag); //将当前页存到dom上 callback(flag); } this.PaginationMetaData = function(data){ //假分页数据,每页10条数据 // data = {NewData:{},MetaData:[],PageCount:0,Callback:null}; var newData = {}; var metaData = data.MetaData; var pageCount = data.PageCount; for(let i = 0; i < pageCount; i++){ var itemArr = []; for(let j = 0; j < 10; j++){ var itemIndex = 10*i + j; if(itemIndex <= metaData.length - 1){ var item = metaData[itemIndex]; itemArr.push(item); }else { break; } } newData[i+1] = itemArr; } data.NewData = newData; } //显示 this.DoModal=function(event) { var chart=event.data.Chart; if (this.ID==null) this.Create(); //第1次 需要创建div this.MatchData=event.data.MatchData; this.Sample=event.data.Sample; this.HQChart=chart; this.BindData(); //居中显示 var border=chart.Frame.ChartBorder; var scrollPos=GetScrollPosition(); var left=border.GetWidth()/2; var top=border.GetHeight()/2; this.Show(left,top,200,200); //显示 } } //等待动画窗口 function WaitDialog(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.Title='加载中......'; this.Dialog; //隐藏窗口 this.Close=function() { if (this.Dialog) { this.DivElement.removeChild(this.Dialog); this.Dialog=null; } } this.SetTitle=function(title) { this.Title=title; if (!this.Dialog) return; //TODO: 更新标题数据 } this.Create=function() { this.ID=Guid(); var div=document.createElement('div'); div.className='jchart-wait-box'; div.id=this.ID; div.innerHTML= `
      ${this.Title}
      `.trim(); this.DivElement.appendChild(div); this.Dialog=div; } //显示 this.DoModal=function(event) { this.Title=event.data.Title; var chart=event.data.Chart; if (this.ID==null) this.Create(); //第1次 需要创建div //居中显示 var border=chart.Frame.ChartBorder; var scrollPos=GetScrollPosition(); var left=border.GetWidth()/2; var top=border.GetHeight()/2; this.Show(left,top,200,40); //显示 } } //K线右键菜单类 //id:"kline" function KLineRightMenu(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.option={}; this.Create = function () { var _self = this; this.ID=Guid(); _self.BindData(); _self.BindEvent(); } this.BindData=function(){ var _self = this; var id=this.DivElement.id; var $body = $("#" + id); $body.find("div[id^='topMenu_']").remove(); $body.find("div[id^='childMenu_']").remove(); var $topMenu = $("
      "); $topMenu.attr("id", "topMenu_"+_self.ID).addClass("context-menu-wrapper topmenu").hide(); $body.append($topMenu); var $topTable = $(""); $topTable.attr({ id: "topTable_" + _self.ID, cellspacing: "0", cellpadding: "0" }).addClass("context-menu"); $topMenu.append($topTable); $topTable.append(_self.childrenList(_self.option.data)); for (var i = 0; i < _self.option.data.length; i++) { var isHasChildren = typeof _self.option.data[i].children != "undefined"; if (isHasChildren) { var $childMenu = $("
      "); $childMenu.attr({ id: "childMenu_"+_self.ID + i, "data-index": i }).addClass("context-menu-wrapper").hide(); $body.append($childMenu); var $childTable = $("
      "); $childTable.attr({ id: "childTable_" + _self.ID + i, cellspacing: "0", cellpadding: "0" }).addClass("context-menu"); $childMenu.append($childTable); $childTable.append(_self.childrenList(_self.option.data[i].children)); } } } this.Update=function() { var _self = this; //var id=this.DivElement.id; //var $body=$("#"+id); // //var $topTable = $("#topTable_" + _self.ID); //$topTable.empty(); //$topTable.append(_self.childrenList(_self.option.data)); // //for (var i = 0; i < _self.option.data.length; i++) { // var isHasChildren = typeof _self.option.data[i].children != "undefined"; // // if (isHasChildren) { // var $childTable = $("#childTable_" + _self.ID + i); // $childTable.empty(); // $childTable.append(_self.childrenList(_self.option.data[i].children)); // } //} _self.BindData(); _self.BindEvent(); } this.childrenList = function(list) { var result = []; for (var i = 0; i < list.length; i++) { var isBorder = typeof list[i].isBorder != "undefined" && list[i].isBorder; var $tr = $(""); $tr.addClass("font_Arial context-menu"); if (isBorder) $tr.addClass("border"); var $td1 = $("
      "); if(list[i].selected){ $td1.addClass("spacer context-menu").html("√"); }else{ $td1.addClass("spacer context-menu"); } var $td2 = $(""); $td2.addClass("text").html(list[i].text); var $td3 = $(""); $td3.addClass("right shortcut"); var $td4 = $(""); $td4.addClass(typeof list[i].children != "undefined" ? "submenu-arrow" : "context-menu spacer"); $tr.append($td1).append($td2).append($td3).append($td4); result.push($tr); } return result; } this.Show=function (obj) { var _self = this; $.extend(_self.option, obj); if (!_self.ID) _self.Create(); //判断是否重复创建 else _self.Update(); //更新菜单状态 var $topMenu = $("#topMenu_"+_self.ID), topWidth = $topMenu.outerWidth(), topHeight = $topMenu.outerHeight(); var x = _self.option.x, y = _self.option.y; if (topWidth > _self.option.position.X + _self.option.position.W- x) //超过了右边距 x = x - topWidth; if (topHeight > _self.option.position.Y +_self.option.position.H - y)//超过了下边距 y = y - topHeight; $topMenu.hide(); $topMenu.css({ position:"absolute",left: x + "px", top: y + "px" }).show(); this.isInit = true; } this.Hide=function () { var _self = this; $("#topMenu_" + _self.ID).hide(); $("[id^='childMenu_" + _self.ID + "']").hide(); } this.BindEvent=function () { var _self = this; var $childMenu = $("[id^='childMenu_" + _self.ID + "']"); $("#topTable_" + _self.ID).find("tr").mouseenter(function () { var $this = $(this), index = $this.index(), $topMenu = $("#topMenu_" + _self.ID), $child = $("#childMenu_" + _self.ID + index), trWidth = $this.outerWidth(), trHeight = $this.outerHeight(); var left = $topMenu.position().left + trWidth + 1; var top = $topMenu.position().top + (trHeight * index); if (trWidth > _self.option.position.X + _self.option.position.W - left) //超过了右边距 left = left - trWidth - $topMenu.outerWidth() - 2; if ($child.outerHeight() > _self.option.position.Y +_self.option.position.H - top)//超过了下边距 top = $topMenu.position().top + $topMenu.outerHeight() - $child.outerHeight(); $childMenu.hide(); $child.css({ left: left + "px", top: top + "px" }).show(); }).mouseleave(function () { var index = $(this).index(); setTimeout(function () { if ($("#childMenu_" + _self.ID + index).attr("data-isShow") != 1) { $("#childMenu_" + _self.ID + index).hide(); } }, 10) }).click(function () { var $this = $(this); var index = $this.index(); if ($.type(_self.option.data[index].click) == "function") { _self.option.data[index].click(_self.option.returnData); $this.hide(); } }); $childMenu.mouseenter(function () { $(this).attr("data-isShow", "1"); }).mouseleave(function () { $(this).attr("data-isShow", "0"); }); $childMenu.find("tr").click(function () { var $this = $(this); var divIndex = parseInt($this.closest("div").attr("data-index")); var trIndex = $this.index(); if ($.type(_self.option.data[divIndex].children[trIndex].click) == "function") { _self.option.data[divIndex].children[trIndex].click(_self.option.windowIndex || 1); $childMenu.hide(); } }); } this.GetPeriod=function (chart) { var data= [ { text: "日线", Value:0, click: function () { chart.ChangePeriod(0); } }, { text: "周线",Value:1, click: function () { chart.ChangePeriod(1); } }, { text: "月线",Value:2, click: function () { chart.ChangePeriod(2); } }, { text: "季线",Value:9, click: function () { chart.ChangePeriod(9); } }, { text: "年线",Value:3, click: function () { chart.ChangePeriod(3); } }, { text: "1分",Value:4, click: function () { chart.ChangePeriod(4); } }, { text: "5分",Value:5, click: function () { chart.ChangePeriod(5); } }, { text: "15分",Value:6, click: function () { chart.ChangePeriod(6); } }, { text: "30分",Value:7, click: function () { chart.ChangePeriod(7); } }, { text: "60分",Value:8, click: function () { chart.ChangePeriod(8); } }, { text: "2小时",Value:11, click: function () { chart.ChangePeriod(11); } }, { text: "4小时",Value:12, click: function () { chart.ChangePeriod(12); } }, { text: "分笔",Value:10, click: function () { chart.ChangePeriod(10); } }, { text: "自定义周期:3分钟",Value:20003, click: function () { chart.ChangePeriod(20003); } }, { text: "自定义周期:35分钟",Value:20035, click: function () { chart.ChangePeriod(20035); } }, { text: "自定义周期:8日",Value:40008, click: function () { chart.ChangePeriod(40008); } } ]; for(var i in data) { var item=data[i]; if (item.Value==chart.Period) { item.selected=true; break; } } return data; } this.GetRight=function(chart) { var data= [ { text: "不复权", click: function () { chart.ChangeRight(0); } }, { text: "前复权", click: function () { chart.ChangeRight(1); } }, { text: "后复权", click: function () { chart.ChangeRight(2); } } ]; if (chart.Right>=0 && chart.Right0) { data[data.length-1].isBorder=true; data.push( { text: "取消叠加", click: function () { chart.ClearOverlaySymbol();} } ); } return data; } //K线类型设置 this.GetKLineType=function(chart) { var data= [ { text: "K线(空心阳线)", click: function () { chart.ChangeKLineDrawType(3);} }, { text: "K线(实心阳线)", click: function () { chart.ChangeKLineDrawType(0); } }, { text: "美国线", click: function () { chart.ChangeKLineDrawType(2); } }, { text: "收盘线", click: function () { chart.ChangeKLineDrawType(1); } }, { text: "收盘面积", click: function () { chart.ChangeKLineDrawType(4); } } ]; switch(chart.KLineDrawType) { case 0: data[1].selected=true; break; case 1: data[3].selected=true; break; case 2: data[2].selected=true; break; case 3: data[0].selected=true; break; case 4: data[4].selected=true; break; } return data; } //指标窗口个数 this.GetIndexWindowCount=function(chart) { var data= [ { text: "1个窗口", click: function () { chart.ChangeIndexWindowCount(1); } }, { text: "2个窗口", click: function () { chart.ChangeIndexWindowCount(2); } }, { text: "3个窗口", click: function () { chart.ChangeIndexWindowCount(3); } }, { text: "4个窗口", click: function () { chart.ChangeIndexWindowCount(4); } }, { text: "5个窗口", click: function () { chart.ChangeIndexWindowCount(5); } } ]; var count=chart.Frame.SubFrame.length; if ((count-1)>=0 && (count-1)0) { if (chart.Frame.SubFrame[0].Frame.CoordinateType==1) data[2].selected=true; else data[0].selected=true; if (chart.Frame.SubFrame[0].Frame.YSplitOperator.CoordinateType==1) data[1].selected=true; } return data; } //拖拽模式 this.GetDragModeType=function(chart) { var data= [ { text: "禁止拖拽", click: function () { chart.DragMode=0; } }, { text: "启动拖拽", click: function () { chart.DragMode=1; } }, { text: "区间选择", click: function () { chart.DragMode=2; } } ]; if (chart.DragMode>=0 && chart.DragMode0) { data[data.length-1].isBorder=true; var item={ text:'删除所有', click:function() { chart.ClearKLineInfo()} }; data.push(item); } return data; } this.CreateKlineInfoItem=function(infoName,bExist,chart) { var item= { text:infoName, selected:bExist } if (bExist) item.click=function() { chart.DeleteKLineInfo(infoName) }; else item.click=function() { chart.AddKLineInfo(infoName,true) } return item; } this.DoModal=function(event) { var chart=event.data.Chart; var rightMenu=chart.RightMenu; var x = event.offsetX; var y = event.offsetY; var dataList=[{ text: "分析周期", children: this.GetPeriod(chart) }, { text: "复权处理", children: this.GetRight(chart) }, { text: "指标切换", children: this.GetIndex(chart) }, { text:"五彩K线", children: this.GetColorIndex(chart) }, { text:'专家系统', children: this.GetTradeIndex(chart) }, { text:'信息地雷', children: this.GetKLineInfo(chart) }, { text: "叠加品种", children: this.GetOverlay(chart) }, { text:'主图线型', children: this.GetKLineType(chart) }, { text:"坐标类型", children:this.GetCoordinateType(chart) }, { text:'指标窗口个数', children: this.GetIndexWindowCount(chart) }, { text:'鼠标拖拽', children: this.GetDragModeType(chart) }, { text:"工具", children:this.GetTools(chart) } ]; var upperSymbol=chart.Symbol.toUpperCase(); if(MARKET_SUFFIX_NAME.IsSHSZIndex(chart.Symbol) || MARKET_SUFFIX_NAME.IsBIT(upperSymbol)) { dataList.splice(1,1); } var identify=event.data.FrameID; var overlayIndex=this.GetOverlayIndex(chart,identify); if (overlayIndex && overlayIndex.length>0) { var delOverlayIndexMenu={ text:'删除叠加指标', children:this.GetDeleteOverlayIndex(chart,overlayIndex) } dataList.splice(3,0,delOverlayIndexMenu); } console.log('[KLineRightMenu::DoModal]',identify); rightMenu.Show({ windowIndex :identify, x:x+chart.UIElement.offsetLeft, y:y+chart.UIElement.offsetTop, position:chart.Frame.Position, data:dataList }) $(document).click(function () { rightMenu.Hide(); }); } this.GetOverlayIndex=function(chart, windowsIndex) { if (windowsIndex>=chart.Frame.SubFrame.length) return []; var result=[]; var item=chart.Frame.SubFrame[windowsIndex]; for(var i in item.OverlayIndex) { var overlayItem=item.OverlayIndex[i]; result.push({Name:overlayItem.Script.Name, Identify:overlayItem.Identify}); } return result; } this.GetDeleteOverlayIndex=function(chart,overlayIndex) { var data=[]; for(var i in overlayIndex) { let identify=overlayIndex[i].Identify; data.push({text:overlayIndex[i].Name, click:function() { chart.DeleteOverlayWindowsIndex(identify) }}); } return data; } } //K线区间选择右键菜单 function KLineSelectRightMenu(divElement) { this.newMethod=KLineRightMenu; //派生 this.newMethod(divElement); delete this.newMethod; this.DoModal=function(event) { var chart=event.data.Chart; var rightMenu=this; var x = event.data.X; var y = event.data.Y; var dataList= [ { text: "区间统计", click: function () { console.log('[KLineSelectRightMenu::click] 区间统计'); var dialog=new KLineSelectRectDialog(divElement); dialog.DoModal(event); } } ]; rightMenu.Show({ x:x, y:y, position:chart.Frame.Position, data:dataList }); } this.Show=function (obj) { var _self = this; $.extend(_self.option, obj); //判断是否重复创建 if (!_self.ID) _self.Create(); var $topMenu = $("#topMenu_"+_self.ID), topWidth = $topMenu.outerWidth(), topHeight = $topMenu.outerHeight(); var x = _self.option.x, y = _self.option.y; if (topWidth > _self.option.position.X + _self.option.position.W- x) //超过了右边距 x = x - topWidth; if (topHeight > _self.option.position.Y +_self.option.position.H - y)//超过了下边距 y = y - topHeight; $topMenu.hide(); $topMenu.css({ position:"absolute",left: x + "px", top: y + "px" }).show(); $("#topMenu_" + _self.ID).find("tr").show(); //把菜单列表显示 this.isInit = true; } } //分钟数据右键菜单 function MinuteRightMenu(divElement) { this.newMethod=KLineRightMenu; //派生 this.newMethod(divElement); delete this.newMethod; this.DoModal=function(event) { var chart=event.data.Chart; var rightMenu=chart.RightMenu; var x = event.offsetX; var y = event.offsetY; var dataList= [ { text: "叠加品种", children: this.GetOverlay(chart) }, { text: "多日分时图", children: this.GetDayCount(chart) }, { text:'指标窗口个数', children: this.GetIndexWindowCount(chart) }, { text: "副图指标切换", children: this.GetIndex(chart) } ]; var symbol=chart.Symbol; if (MARKET_SUFFIX_NAME.IsSHSZStockA(symbol)) { dataList.push({text:'集合竞价',children: this.GetShowBeforeData(chart)}); } var identify=event.data.FrameID; console.log('[MinuteRightMenu::DoModal]',identify); rightMenu.Show({ windowIndex :identify, x:x+chart.UIElement.offsetLeft, y:y+chart.UIElement.offsetTop, position:chart.Frame.Position, data:dataList }) $(document).click(function () { rightMenu.Hide(); }); } this.GetDayCount=function(chart) { var data= [ { text: "当日分时图", click: function () { chart.ChangeDayCount(1); }, isBorder:true }, { text: "最近2日", click: function () { chart.ChangeDayCount(2); } }, { text: "最近3日", click: function () { chart.ChangeDayCount(3); } }, { text: "最近4日", click: function () { chart.ChangeDayCount(4); } }, { text: "最近5日", click: function () { chart.ChangeDayCount(5); } }, { text: "最近6日", click: function () { chart.ChangeDayCount(6); } } ]; if ((chart.DayCount-1)>=0 && (chart.DayCount-1)=0 && (count-1)'+ ''+ '\n' + ''+ ''; }else{ toolsDiv = '

      ' + '

      \n' + '

      '; } this.SubToolsDiv.style.right = right + "px"; this.SubToolsDiv.style.top = top + "px"; this.SubToolsDiv.innerHTML = toolsDiv; this.SubToolsDiv.style.position = "absolute"; this.SubToolsDiv.style.display = "block"; var hqChart = this.HQChart; var picture = this.ChartPicture; var subToolDiv = this.SubToolsDiv; $(".subtool-del").click(function(){ hqChart.ClearChartDrawPicture(picture); // subToolDiv.innerHTML = ""; $(".subTolls").css("display","none"); }); var self = this; $(".subtool-set").click(function(){ $(self.SubToolsDiv).hide(); //创建div设置窗口 if (!this.SettingMenu) self.SettingMenu=new ChartPictureTextSettingMenu(frame.ChartBorder.UIElement.parentNode); self.SettingMenu.ChartPicture=picture; self.SettingMenu.HQChart=hqChart; self.SettingMenu.Position={Left:right + 80,Top:top + 20}; self.SettingMenu.DoModal(); }); $(".changes-color").click(function () { document.getElementById('color').click(); $(".change-color").change(function () { var color = $(".change-color").val(); picture.LineColor = color; picture.PointColor = color; if (hqChart.ChartDrawStorage) hqChart.ChartDrawStorage.SaveDrawData(picture); //保存下 }); }) console.log("[ChartPictureSettingMenu::DoModal]", {Top:top,Left:left, Right:right}); } } //画图工具 文本设置窗口 function ChartPictureTextSettingMenu(divElement) { this.newMethod=IDivDialog; //派生 this.newMethod(divElement); delete this.newMethod; this.ChartPicture; this.SettingDiv; this.Position; this.BackupData; //画图工具备份数据 this.Close=function() { if (this.SettingDiv) this.DivElement.removeChild(this.SettingDiv); //直接删除 } this.DoModal=function() { var text=this.ChartPicture.Text; //显示的文本 var fontOption=this.ChartPicture.FontOption; //字体设置 var lineColor=this.ChartPicture.LineColor; //数据备份, 点取消的时候把备份数据设置回去 this.BackupData= { Text:text, LineColor:lineColor, FontOption:{Family: fontOption.Family, Size: fontOption.Size, Weight: fontOption.Weight, Style: fontOption.Style } }; console.log('[ChartPictureTextSettingMenu::DoModal] picture info',this.BackupData); var self=this; var div=this.DivElement.getElementsByClassName('chartpicture-text-setting')[0]; if (!div) { div=document.createElement("div"); div.className='chartpicture-text-setting'; this.DivElement.appendChild(div); this.SettingDiv=div; } else { this.SettingDiv=div; } var titleContainerStr = '
      '+ '样式设置'+ ''+ '
      '; var fontSizeArray = [10,11,12,14,16,20,24,28,32,40]; var fontArray = ['微软雅黑','宋体','Arial','仿宋']; var sizeListStr = ""; var fontListStr = ""; fontArray.forEach(function(item,index){ fontListStr += index !== 0 ? '

      '+item+'

      ' : '

      '+item+'

      '; }); fontSizeArray.forEach(function(item,index){ sizeListStr += index !== 5 ? '

      '+item+'

      ' : '

      '+item+'

      '; }); var contentContainerStr = '
      '+ '
      '+ ''+ '
      微软雅黑
      '+fontListStr+'
      '+ '
      20
      '+sizeListStr+'
      '+ ''+ ''+ '
      '+ ''+ '
      '; var btnContainer = '
      '+ '确认'+ '取消'+ '
      '; var DoModalStr = titleContainerStr+contentContainerStr+btnContainer; this.SettingDiv.style.left = this.Position.Left + "px"; this.SettingDiv.style.top = this.Position.Top + "px"; this.SettingDiv.innerHTML=DoModalStr; this.SettingDiv.style.position = "absolute"; this.SettingDiv.style.display = "block"; $(".chartpicture-text-setting .colorPicker").css({ //初始设置 "borderColor":self.ChartPicture.LineColor, "background-color":self.ChartPicture.LineColor }); var family = this.ChartPicture.FontOption.Family; $('.chartpicture-text-setting .fontSelect .choicedText').html(family); fontArray.forEach(function(item,index){ if(item == family){ $('.chartpicture-text-setting .fontSelect p').removeClass('active'); $('.chartpicture-text-setting .fontSelect p').eq(index).addClass('active'); } }); var size = this.ChartPicture.FontOption.Size; $('.chartpicture-text-setting .fontSizeSelect .choicedText').html(size); fontSizeArray.forEach(function(item,index){ if(item == size){ $('.chartpicture-text-setting .fontSizeSelect p').removeClass('active'); $('.chartpicture-text-setting .fontSizeSelect p').eq(index).addClass('active'); } }); var weight = this.ChartPicture.FontOption.Weight; if( weight != null && weight == 'bold'){ $('.chartpicture-text-setting .strongFont').addClass('hot'); } var style = this.ChartPicture.FontOption.Style; if( style != null && style == 'italic'){ $('.chartpicture-text-setting .italicsFont').addClass('hot'); } var text = this.ChartPicture.Text; $('.chartpicture-text-setting .tArea').val(text); //结束初始设置 var defaultTextOption = { Family:'微软雅黑', Size:20, Weight:null, Style:null }; $(".chartpicture-text-setting #fontColor").change( { Picture:this.ChartPicture }, function(event) { //颜色选择 var value = $(this).val(); $(this).parent().css({ "borderColor":value, "background-color":value }); var chart=event.data.Picture; chart.LineColor = value; if (chart.Update) chart.Update(); //更新界面 } ); $(".chartpicture-text-setting .fontSelect,.chartpicture-text-setting .fontSizeSelect").click(function(){ $(this).find('.selectList').toggle(); $(this).toggleClass('hot'); }); $(".chartpicture-text-setting .fontSelect p").click( { Picture:this.ChartPicture }, function(event){ //字体选择 var choicedText = $(this).closest(".fontSelect").find('.choicedText').html(); var currentSelect = event.currentTarget.innerHTML; if(choicedText !== currentSelect){ $(this).closest(".fontSelect").find('.choicedText').html(currentSelect); $(this).siblings().removeClass('active'); $(this).addClass('active'); var chart = event.data.Picture; chart.FontOption.Family = currentSelect; if (chart.Update) chart.Update(); //更新界面 } }); $(".chartpicture-text-setting .fontSizeSelect p").click( { Picture:this.ChartPicture }, function(event){ //字号选择 var choicedText = $(this).closest(".fontSizeSelect").find('.choicedText').html(); var currentSelect = event.currentTarget.innerHTML; if(choicedText !== currentSelect){ $(this).closest(".fontSizeSelect").find('.choicedText').html(currentSelect); $(this).siblings().removeClass('active'); $(this).addClass('active'); var chart = event.data.Picture; chart.FontOption.Size = Number(currentSelect); if (chart.Update) chart.Update(); //更新界面 } }); $(".chartpicture-text-setting .strongFont").click( { Picture:this.ChartPicture }, function(event){ $(this).toggleClass('hot'); var classnames = $(this).attr('class'); if(classnames.indexOf('hot') > 0){ var chart = event.data.Picture; chart.FontOption.Weight = 'bold'; if (chart.Update) chart.Update(); //更新界面 } }); $(".chartpicture-text-setting .italicsFont").click( { Picture:this.ChartPicture }, function(event){ $(this).toggleClass('hot') var classnames = $(this).attr('class'); if(classnames.indexOf('hot') > 0){ var chart = event.data.Picture; chart.FontOption.Style = 'italic'; if (chart.Update) chart.Update(); //更新界面 } }); $(".chartpicture-text-setting .titleWrap .closeBtn,.chartpicture-text-setting .btnsContainer .cancelBtn").click( //取消 { Picture:this.ChartPicture }, function(event){ var picture = event.data.Picture; picture.Text = self.BackupData.Text; picture.LineColor = self.BackupData.LineColor; picture.FontOption = self.BackupData.FontOption; if (picture.Update) picture.Update(); self.Close(); }); $(".chartpicture-text-setting .tArea").keyup( //文本内容 { Picture:this.ChartPicture }, function(event){ console.log('[ChartPictureTextSettingMenu::DoModal] $(".chartpicture-text-setting .tArea").keyup()'); var content = $(this).val(); var chart = event.data.Picture; chart.Text = content; if (chart.Update) chart.Update(); //更新界面 }); //确定按钮 $(".chartpicture-text-setting .btnsContainer .okBtn").click( function() { self.Close(); if (self.HQChart && self.HQChart.ChartDrawStorage) self.HQChart.ChartDrawStorage.SaveDrawData(self.ChartPicture); //保存下 } ); } } /////////////////////////////////////////////////////////////////////////////////////// // // 各个品种分钟走势图坐标信息 // ////////////////////////////////////////////////////////////////////////////////////// var MARKET_SUFFIX_NAME= { SH:'.SH', SZ:'.SZ', HK:'.HK', //港股 FHK:'.FHK', //港股期货 SHFE: '.SHF', //上期所 (Shanghai Futures Exchange) SHFE2:'.SHFE', //上期所 (Shanghai Futures Exchange) CFFEX: '.CFE', //中期所 (China Financial Futures Exchange) DCE: '.DCE', //大连商品交易所(Dalian Commodity Exchange) CZCE: '.CZC', //郑州期货交易所 USA:'.USA', //美股 FTSE:'.FTSE', //富时中国 BIT:'.BIT', //数字货币 如比特币 BIZ:'.BIZ', //数字货币 ET:'.ET', //其他未知的品种 IsET:function(upperSymbol) { if (!upperSymbol) return false; return upperSymbol.indexOf(this.ET) > 0; }, IsFTSE:function(upperSymbol) { if (!upperSymbol) return false; return upperSymbol.indexOf(this.FTSE) > 0; }, IsFHK:function(upperSymbol) { if (!upperSymbol) return false; return upperSymbol.indexOf(this.FHK) > 0; }, IsBIT:function(upperSymbol) { if (!upperSymbol) return false; if (upperSymbol.indexOf(this.BIT) > 0) return true; if (upperSymbol.indexOf(this.BIZ) > 0) return true; return false; }, IsUSA:function(upperSymbol) //是否是美股 { if (!upperSymbol) return false; return upperSymbol.indexOf(this.USA) > 0; }, IsSH: function (upperSymbol) { //需要精确匹配最后3位 var pos = upperSymbol.length-this.SH.length; var find = upperSymbol.indexOf(this.SH); return find == pos; }, IsSZ: function (upperSymbol) { var pos = upperSymbol.length - this.SZ.length; var find = upperSymbol.indexOf(this.SZ); return find == pos; }, IsHK: function (upperSymbol) { var pos = upperSymbol.length - this.HK.length; var find = upperSymbol.indexOf(this.HK); return find == pos; }, IsSHFE: function (upperSymbol) { if (!upperSymbol) return false; if (upperSymbol.indexOf(this.SHFE) > 0) return true; if (upperSymbol.indexOf(this.SHFE2) > 0) return true; return false; }, IsCFFEX: function (upperSymbol) { return upperSymbol.indexOf(this.CFFEX) > 0; }, IsDCE: function (upperSymbol) { return upperSymbol.indexOf(this.DCE) > 0; }, IsCZCE: function (upperSymbol) { return upperSymbol.indexOf(this.CZCE) > 0; }, IsChinaFutures:function(upperSymbol) //是否是国内期货 { return this.IsCFFEX(upperSymbol) || this.IsCZCE(upperSymbol) || this.IsDCE(upperSymbol) || this.IsSHFE(upperSymbol); }, IsSHSZ:function(upperSymbol) //是否是沪深的股票 { return this.IsSZ(upperSymbol)|| this.IsSH(upperSymbol); }, IsSHSZFund:function(upperSymbol) //是否是交易所基金 { if (!upperSymbol) return false; if (this.IsSH(upperSymbol)) //51XXXX.SH { if (upperSymbol.charAt(0)=='5' && upperSymbol.charAt(1)=='1') return true; } else if (this.IsSZ(upperSymbol)) //15XXXX.sz, 16XXXX.sz, 17XXXX.sz, 18XXXX.sz { if (upperSymbol.charAt(0)=='1' && (upperSymbol.charAt(1)=='5' || upperSymbol.charAt(1)=='6' || upperSymbol.charAt(1)=='7' || upperSymbol.charAt(1)=='8') ) return true; } return false; }, IsSHSZIndex:function(symbol) //是否是沪深指数代码 { if (!symbol) return false; var upperSymbol=symbol.toUpperCase(); if (this.IsSH(upperSymbol)) { var temp=upperSymbol.replace('.SH',''); if (upperSymbol.charAt(0)=='0' && parseInt(temp)<=3000) return true; } else if (this.IsSZ(upperSymbol)) { if (upperSymbol.charAt(0)=='3' && upperSymbol.charAt(1)=='9') return true; } else if (upperSymbol.indexOf('.CI')>0) //自定义指数 { return true; } return false; }, IsSHSZStockA:function(symbol) //是否是沪深A股 { if (!symbol) return false; var upperSymbol=symbol.toUpperCase(); if (this.IsSH(upperSymbol)) { var temp=upperSymbol.replace('.SH',''); if (upperSymbol.charAt(0)=='6') return true; } else if (this.IsSZ(upperSymbol)) { if (upperSymbol.charAt(0)=='0') { if (upperSymbol.charAt(1)=='0' && upperSymbol.charAt(1)=='2') return true; //002 中小板 if (upperSymbol.charAt(1)!='7' && upperSymbol.charAt(1)!='8') return true; } } return false; }, IsSHStockSTAR:function(symbol) // 是否是科创板 Sci-Tech innovAtion boaRd (STAR Market) { if (!symbol) return false; var upperSymbol=symbol.toUpperCase(); if (!this.IsSH(upperSymbol)) return false; if (upperSymbol.charAt(0)=='6' && upperSymbol.charAt(1)=='8' && upperSymbol.charAt(2)=='8') return true; return false; }, GetMarketStatus:function(symbol) //获取市场状态 0=闭市 1=盘前 2=盘中 3=盘后 { if (!symbol) return 0; var upperSymbol=symbol.toUpperCase(); var nowDate= new Date(); var day = nowDate.getDay(); var time = nowDate.getHours() * 100 + nowDate.getMinutes(); if (this.IsUSA(upperSymbol)) { var usaDate=GetLocalTime(-4); var day = usaDate.getDay(); var time = usaDate.getHours() * 100 + usaDate.getMinutes(); if(day == 6 || day== 0) return 0; //周末 //9:30 - 16:00 考虑夏令时间时间增加1小时 9:30 - 17:00 if (time>1730) return 3; if (time<930) return 1; return 2; } else if (this.IsBIT(upperSymbol)) //数字货币24小时 { return 2; } else if (this.IsFTSE(upperSymbol)) //富时中国 9:00-16:30 17:00-04:45 { if(day == 6 || day== 0) return 0; //周末 if (time>=830 && time<=2359) return 2; if (time>=0 && time<=500) return 2; return 0; } else if (this.IsFHK(upperSymbol)) //港股指数期货 9:15-12:00 13:00-16:30 17:15-01:00 { if(day == 6 || day== 0) return 0; //周末 if (time>=900 && time<=2359) return 2; if (time>=0 && time<=320) return 2; return 0; } else if (this.IsET(upperSymbol)) { return this.GetETMarketStatus(symbol); } else //9:30 - 15:40 { if(day == 6 || day== 0) return 0; //周末 if(time>1540) return 3; if(time<925) return 1; return 2; } }, GetLimitPriceRange:function(symbol, name) //涨停范围 { if (!this.IsSHSZStockA(symbol)) return null; if (this.IsSHStockSTAR(symbol)) return {Max:0.2 , Min:-0.2}; //科创板 [20%- -20%] if (!name) return null; if (name.indexOf('ST')>=0) return { Max:0.05, Min:-0.05 }; //ST 股票 [5% - -5%] return {Max:0.1 , Min:-0.1}; //[10% - -10%] }, GetFHKDecimal:function(symbol) //港股指数期货 小数位数 { return 0; }, GetFTSEDecimal:function(symbol) //富时中国A50期货 小数位数 { return 0; }, GetBITDecimal:function(symbol) { return 2; }, GetETDecimal:function(symbol) { return 2; }, GetETMarketStatus:function(symbol) { // 0=闭市 1=盘前 2=盘中 3=盘后 return 2; } } //走势图分钟数据对应的时间 function MinuteTimeStringData() { this.SHSZ = null; //上海深证交易所时间 this.HK = null; //香港交易所时间 this.Futures=new Map(); //期货交易时间 key=时间名称 Value=数据 this.USA = null; //美股交易时间 this.FTSE=null; //富时中国 this.FHK=null; //港股指数期货 this.Initialize = function () //初始化 默认只初始化沪深的 其他市场动态生成 { //this.SHSZ = this.CreateSHSZData(); //this.HK = this.CreateHKData(); } this.GetSHSZ=function() //动态创建 { if (!this.SHSZ) this.SHSZ=this.CreateSHSZData(); return this.SHSZ; } this.GetHK=function() { if (!this.HK) this.HK = this.CreateHKData(); return this.HK; } this.GetFutures=function(splitData) { if (!this.Futures.has(splitData.Name)) { var data = this.CreateTimeData(splitData.Data); this.Futures.set(splitData.Name,data); } return this.Futures.get(splitData.Name); } this.GetUSA=function() { if (!this.USA) this.USA=this.CreateUSAData(0); return this.USA; } this.GetFTSE=function() { if (!this.FTSE) this.FTSE=this.CreateFTSEData(); return this.FTSE; } this.GetFHK=function() { if (!this.FHK) this.FHK=this.CreateFHKData(); return this.FHK; } this.CreateSHSZData = function () { const TIME_SPLIT = [ { Start: 925, End: 925 }, { Start: 930, End: 1130 }, { Start: 1300, End: 1500 } ]; return this.CreateTimeData(TIME_SPLIT); } this.CreateHKData = function () { const TIME_SPLIT = [ { Start: 930, End: 1200 }, { Start: 1300, End: 1600 } ]; return this.CreateTimeData(TIME_SPLIT); } this.CreateFTSEData=function() { const TIME_SPLIT= [ { Start:1700, End:2359 }, { Start:0, End:445 }, { Start:900, End:1630 } ]; return this.CreateTimeData(TIME_SPLIT); } this.CreateFHKData=function() { //港股指数期货 9:15-12:00 13:00-16:30 17:15-03:00 const TIME_SPLIT= [ { Start:1715, End:2359 }, { Start:0, End:300 }, { Start:915, End:1200 }, { Start:1300, End:1630 }, ]; return this.CreateTimeData(TIME_SPLIT); } this.CreateUSAData=function(type) { if (type==1) //美国夏令时 { const TIME_SPLIT = [ { Start: 2130, End: 2359 }, { Start: 0, End: 400 } ]; return this.CreateTimeData(TIME_SPLIT); } else if (type==2) //非夏令时 { const TIME_SPLIT = [ { Start: 2230, End: 2359 }, { Start: 0, End: 500 } ]; return this.CreateTimeData(TIME_SPLIT); } else //使用美国本地时间 { const TIME_SPLIT = [ { Start: 930, End: 1600 } //美国东部时间9:30到16:00 ]; return this.CreateTimeData(TIME_SPLIT); } } this.CreateTimeData = function (timeSplit) { var data = []; for (var i in timeSplit) { var item = timeSplit[i]; for (var j = item.Start; j <= item.End; ++j) { if (j % 100 >= 60) continue; //大于60分钟的数据去掉 data.push(j); } } return data; } this.GetTimeData = function (symbol) { if (!symbol) return this.SHSZ; var upperSymbol = symbol.toLocaleUpperCase(); //转成大写 if (MARKET_SUFFIX_NAME.IsSH(upperSymbol) || MARKET_SUFFIX_NAME.IsSZ(upperSymbol)) return this.GetSHSZ(); if (MARKET_SUFFIX_NAME.IsHK(upperSymbol)) return this.GetHK(); if (MARKET_SUFFIX_NAME.IsUSA(upperSymbol)) return this.GetUSA(true); if (MARKET_SUFFIX_NAME.IsCFFEX(upperSymbol) || MARKET_SUFFIX_NAME.IsCZCE(upperSymbol) || MARKET_SUFFIX_NAME.IsDCE(upperSymbol) || MARKET_SUFFIX_NAME.IsSHFE(upperSymbol)) { var splitData = g_FuturesTimeData.GetSplitData(upperSymbol); if (!splitData) return null; return this.GetFutures(splitData); } if (MARKET_SUFFIX_NAME.IsFTSE(upperSymbol)) return this.GetFTSE(); if (MARKET_SUFFIX_NAME.IsFHK(upperSymbol)) return this.GetFHK(); } } //走势图刻度分钟线 function MinuteCoordinateData() { //沪深走势图时间刻度 const SHZE_MINUTE_X_COORDINATE = { Full: //完整模式 [ [0, 0, "rgb(200,200,200)", "09:30"], [31, 0, "RGB(200,200,200)", "10:00"], [61, 0, "RGB(200,200,200)", "10:30"], [91, 0, "RGB(200,200,200)", "11:00"], [122, 1, "RGB(200,200,200)", "13:00"], [152, 0, "RGB(200,200,200)", "13:30"], [182, 0, "RGB(200,200,200)", "14:00"], [212, 0, "RGB(200,200,200)", "14:30"], [242, 1, "RGB(200,200,200)", "15:00"], // 15:00 ], Simple: //简洁模式 [ [0, 0, "rgb(200,200,200)", "09:30"], [61, 0, "RGB(200,200,200)", "10:30"], [122, 1, "RGB(200,200,200)", "13:00"], [182, 0, "RGB(200,200,200)", "14:00"], [242, 1, "RGB(200,200,200)", "15:00"] ], Min: //最小模式 [ [0, 0, "rgb(200,200,200)", "09:30"], [122, 1, "RGB(200,200,200)", "13:00"], [242, 1, "RGB(200,200,200)", "15:00"] ], Count: 243, MiddleCount: 122, GetData: function (width) { if (width < 200) return this.Min; else if (width < 400) return this.Simple; return this.Full; } }; //港股走势图时间刻度 const HK_MINUTE_X_COORDINATE = { Full: //完整模式 [ [0, 1, "RGB(200,200,200)", "09:30"], [30, 0, "RGB(200,200,200)", "10:00"], [60, 1, "RGB(200,200,200)", "10:30"], [90, 0, "RGB(200,200,200)", "11:00"], [120, 1, "RGB(200,200,200)", "11:30"], [151, 0, "RGB(200,200,200)", "13:00"], [181, 1, "RGB(200,200,200)", "13:30"], [211, 0, "RGB(200,200,200)", "14:00"], [241, 1, "RGB(200,200,200)", "14:30"], [271, 0, "RGB(200,200,200)", "15:00"], [301, 1, "RGB(200,200,200)", "15:30"], [331, 1, "RGB(200,200,200)", "16:00"] ], Simple: //简洁模式 [ [0, 1, "RGB(200,200,200)", "09:30"], [60, 1, "RGB(200,200,200)", "10:30"], [120, 1, "RGB(200,200,200)", "11:30"], [211, 0, "RGB(200,200,200)", "14:00"], [271, 0, "RGB(200,200,200)", "15:00"], [331, 1, "RGB(200,200,200)", "16:00"] ], Min: //最小模式 [ [0, 1, "RGB(200,200,200)", "09:30"], [151, 0, "RGB(200,200,200)", "13:00"], [331, 1, "RGB(200,200,200)", "16:00"] ], Count: 332, MiddleCount: 151, GetData: function (width) { if (width < 200) return this.Min; else if (width < 450) return this.Simple; return this.Full; } }; //美股走势图时间刻度 const USA_MINUTE_X_COORDINATE = { /* Full: //完整模式 [ [0, 0, "rgb(200,200,200)", "21:30"], [60, 0, "RGB(200,200,200)", "22:30"], [120, 1, "RGB(200,200,200)", "23:30"], [210, 0, "RGB(200,200,200)", "01:00"], [270, 0, "RGB(200,200,200)", "02:00"], [330, 0, "RGB(200,200,200)", "03:00"], [390, 0, "RGB(200,200,200)", "04:00"], ], Simple: //简洁模式 [ [0, 0, "rgb(200,200,200)", "21:30"], [160, 1, "RGB(200,200,200)", "00:00"], [270, 0, "RGB(200,200,200)", "02:00"], [390, 0, "RGB(200,200,200)", "04:00"], ], Min: //最小模式 [ [0, 0, "rgb(200,200,200)", "21:30"], [160, 1, "RGB(200,200,200)", "00:00"], [390, 0, "RGB(200,200,200)", "04:00"], ], */ //美国本地时间 Full: //完整模式 [ [0, 0, "rgb(200,200,200)", "9:30"], [30, 0, "RGB(200,200,200)", "10:00"], [90, 1, "RGB(200,200,200)", "11:00"], [150, 0, "RGB(200,200,200)", "12:00"], [210, 0, "RGB(200,200,200)", "13:00"], [270, 0, "RGB(200,200,200)", "14:00"], [330, 0, "RGB(200,200,200)", "15:00"], [390, 0, "RGB(200,200,200)", "16:00"], ], Simple: //简洁模式 [ [30, 0, "rgb(200,200,200)", "10:00"], [150, 1, "RGB(200,200,200)", "12:00"], [270, 0, "RGB(200,200,200)", "14:00"], [390, 0, "RGB(200,200,200)", "16:00"], ], Min: //最小模式 [ [30, 0, "rgb(200,200,200)", "10:00"], [210, 1, "RGB(200,200,200)", "13:00"], [390, 0, "RGB(200,200,200)", "16:00"], ], Count: 391, MiddleCount: 211, GetData: function (width) { if (width < 200) return this.Min; else if (width < 400) return this.Simple; return this.Full; } }; //富时中国 const FTSE_MINUTE_X_COORDINATE= { Full: //完整模式 [ [0, 1, "RGB(200,200,200)", "17:00"], //[60, 0, "RGB(200,200,200)", "18:00"], [120, 1, "RGB(200,200,200)", "19:00"], //[180, 0, "RGB(200,200,200)", "20:00"], [240, 1, "RGB(200,200,200)", "21:00"], //[300, 0, "RGB(200,200,200)", "22:00"], [360, 1, "RGB(200,200,200)", "23:00"], //[420, 0, "RGB(200,200,200)", "00:00"], [480, 1, "RGB(200,200,200)", "01:00"], //[540, 0, "RGB(200,200,200)", "02:00"], [600, 1, "RGB(200,200,200)", "03:00"], //[660, 1, "RGB(200,200,200)", "04:00"], [706, 1, "RGB(200,200,200)", "09:00"], //[766, 1, "RGB(200,200,200)", "10:00"], [826, 1, "RGB(200,200,200)", "11:00"], //[886, 1, "RGB(200,200,200)", "12:00"], [946, 1, "RGB(200,200,200)", "13:00"], //[1006, 1, "RGB(200,200,200)", "14:00"], [1066, 1, "RGB(200,200,200)", "15:00"], [1156, 1, "RGB(200,200,200)", "16:30"], ], Simple: //简洁模式 [ [0, 1, "RGB(200,200,200)", "17:00"], //[60, 0, "RGB(200,200,200)", "18:00"], //[120, 1, "RGB(200,200,200)", "19:00"], //[180, 0, "RGB(200,200,200)", "20:00"], [240, 1, "RGB(200,200,200)", "21:00"], //[300, 0, "RGB(200,200,200)", "22:00"], //[360, 1, "RGB(200,200,200)", "23:30"], //[420, 0, "RGB(200,200,200)", "00:00"], [480, 1, "RGB(200,200,200)", "01:00"], //[540, 0, "RGB(200,200,200)", "02:00"], //[600, 1, "RGB(200,200,200)", "03:00"], //[660, 1, "RGB(200,200,200)", "04:00"], [706, 1, "RGB(200,200,200)", "09:00"], //[766, 1, "RGB(200,200,200)", "10:00"], //[826, 1, "RGB(200,200,200)", "11:00"], //[886, 1, "RGB(200,200,200)", "12:00"], [946, 1, "RGB(200,200,200)", "13:00"], //[1006, 1, "RGB(200,200,200)", "14:00"], //[1066, 1, "RGB(200,200,200)", "15:00"], [1156, 1, "RGB(200,200,200)", "16:30"], ], Min: //最小模式 [ [0, 1, "RGB(200,200,200)", "17:00"], [706, 1, "RGB(200,200,200)", "09:00"], [1156, 1, "RGB(200,200,200)", "16:30"], ], Count: 1157, MiddleCount: 707, GetData: function (width) { if (width < 200) return this.Min; else if (width < 450) return this.Simple; return this.Full; } } //港股指数期货 const FHK_MINUTE_X_COORDINATE= { Full: //完整模式 [ [0, 1, "RGB(200,200,200)", "17:15"], [105, 1, "RGB(200,200,200)", "19:00"], [225, 1, "RGB(200,200,200)", "21:00"], [345, 1, "RGB(200,200,200)", "23:00"], [586, 0, "RGB(200,200,200)", "09:15"], [691, 1, "RGB(200,200,200)", "11:00"], [812, 1, "RGB(200,200,200)", "14:00"], [963, 1, "RGB(200,200,200)", "16:30"], ], Simple: //简洁模式 [ [0, 1, "RGB(200,200,200)", "17:15"], [225, 1, "RGB(200,200,200)", "21:00"], [586, 0, "RGB(200,200,200)", "09:15"], [752, 1, "RGB(200,200,200)", "13:00"], [963, 1, "RGB(200,200,200)", "16:30"], ], Min: //最小模式 [ [0, 1, "RGB(200,200,200)", "17:15"], [586, 0, "RGB(200,200,200)", "09:15"], [963, 1, "RGB(200,200,200)", "16:30"], ], Count: 963, MiddleCount: 526, GetData: function (width) { if (width < 200) return this.Min; else if (width < 450) return this.Simple; return this.Full; } } this.GetCoordinateData = function (symbol, width) { var data = null; if (!symbol) { data = SHZE_MINUTE_X_COORDINATE; //默认沪深股票 } else { var upperSymbol = symbol.toLocaleUpperCase(); //转成大写 if (MARKET_SUFFIX_NAME.IsSH(upperSymbol) || MARKET_SUFFIX_NAME.IsSZ(upperSymbol) || MARKET_SUFFIX_NAME.IsSHSZIndex(upperSymbol)) data = this.GetSHSZData(upperSymbol,width); else if (MARKET_SUFFIX_NAME.IsHK(upperSymbol)) data = HK_MINUTE_X_COORDINATE; else if (MARKET_SUFFIX_NAME.IsCFFEX(upperSymbol) || MARKET_SUFFIX_NAME.IsCZCE(upperSymbol) || MARKET_SUFFIX_NAME.IsDCE(upperSymbol) || MARKET_SUFFIX_NAME.IsSHFE(upperSymbol)) return this.GetFuturesData(upperSymbol,width); else if (MARKET_SUFFIX_NAME.IsUSA(upperSymbol)) data = this.GetUSAData(upperSymbol,width); else if (MARKET_SUFFIX_NAME.IsFTSE(upperSymbol,width)) data=this.GetFTSEData(upperSymbol,width); else if (MARKET_SUFFIX_NAME.IsFHK(upperSymbol,width)) data=this.GetFHKData(upperSymbol,width); } //console.log('[MiuteCoordinateData]', width); var result = { Count: data.Count, MiddleCount: data.MiddleCount, Data: data.GetData(width) }; return result; } this.GetSHSZData=function(upperSymbol,width) { var result=SHZE_MINUTE_X_COORDINATE; return result; } this.GetUSAData=function(upperSymbol,width) { var result=USA_MINUTE_X_COORDINATE; return result; } this.GetFuturesData = function (upperSymbol,width) { var splitData = g_FuturesTimeData.GetSplitData(upperSymbol); if (!splitData) return null; var stringData = g_MinuteTimeStringData.GetFutures(splitData); if (!stringData) return null; var result = { Count: stringData.length }; var coordinate=null; var minWidth=200, simpleWidth=480; /* if (splitData.Name =='21:00-1:00,9:00-10:15,10:30-11:30,13:30-15:00') { minWidth=250; simpleWidth=500; } */ if (width < minWidth) coordinate = splitData.Coordinate.Min; else if (width < simpleWidth) coordinate = splitData.Coordinate.Simple; else coordinate = splitData.Coordinate.Full; var data=[]; for(var i=0;i