UNPKG

hqchart

Version:

HQChart - H5, 微信小程序 沪深/港股/数字货币/期货/美股 K线图(kline),走势图,缩放,拖拽,十字光标,画图工具,截图,筹码图. 分析家语法,通达信语法,(麦语法),第3方数据对接

1,406 lines (1,155 loc) 49.3 kB
/* Copyright (c) 2018 jones http://www.apache.org/licenses/LICENSE-2.0 开源项目 https://github.com/jones2000/HQChart jones_2000@163.com 股票买卖5档 (H5版本) 不提供内置测试数据 */ function JSStockInfoChart(divElement) { this.DivElement=divElement; this.JSChartContainer; //表格控件 this.ResizeListener; //大小变动监听 //h5 canvas this.CanvasElement=document.createElement("canvas"); this.CanvasElement.className='jsstockinfo-drawing'; this.CanvasElement.id=Guid(); this.CanvasElement.setAttribute("tabindex",0); if (this.CanvasElement.style) this.CanvasElement.style.outline='none'; if(divElement.hasChildNodes()) { JSConsole.Chart.Log("[JSStockInfoChart::JSStockInfoChart] divElement hasChildNodes", divElement.childNodes); } divElement.appendChild(this.CanvasElement); this.OnSize=function() { //画布大小通过div获取 如果有style里的大小 使用style里的 var height=this.DivElement.offsetHeight; var width=this.DivElement.offsetWidth; if (this.DivElement.style.height && this.DivElement.style.width) { if (this.DivElement.style.height.includes("px")) height=parseInt(this.DivElement.style.height.replace("px","")); if (this.DivElement.style.width.includes("px")) width=parseInt(this.DivElement.style.width.replace("px","")); } this.CanvasElement.height=height; this.CanvasElement.width=width; 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; JSConsole.Chart.Log(`[JSStockInfoChart::OnSize] devicePixelRatio=${window.devicePixelRatio}, height=${this.CanvasElement.height}, width=${this.CanvasElement.width}`); if (this.JSChartContainer && this.JSChartContainer.OnSize) { this.JSChartContainer.OnSize(); } } this.SetOption=function(option) { var chart=this.CreateJSStockInfoChartContainer(option); if (!chart) return false; if (option.OnCreatedCallback) option.OnCreatedCallback(chart); this.JSChartContainer=chart; this.DivElement.JSChart=this; //div中保存一份 if (option.EnableResize==true) this.CreateResizeListener(); if (option.Symbol) { chart.ChangeSymbol(option.Symbol); //下载列表码表 } else { chart.Draw(); } } this.CreateResizeListener=function() { this.ResizeListener = new ResizeObserver((entries)=>{ this.OnDivResize(entries); }); this.ResizeListener.observe(this.DivElement); } this.OnDivResize=function(entries) { JSConsole.Chart.Log("[JSStockInfoChart::OnDivResize] entries=", entries); this.OnSize(); } //切换股票代码接口 this.ChangeSymbol=function(symbol, option) { if (this.JSChartContainer) this.JSChartContainer.ChangeSymbol(symbol,option); } this.CreateJSStockInfoChartContainer=function(option) { var chart=new JSStockInfoChartContainer(this.CanvasElement); chart.Create(option); this.SetChartBorder(chart, option); if (IFrameSplitOperator.IsNonEmptyArray(option.Column)) chart.SetColumn(option.Column); if (IFrameSplitOperator.IsNonEmptyArray(option.HeaderColumn)) chart.SetHeaderColumn(option.HeaderColumn); if (IFrameSplitOperator.IsNonEmptyArray(option.MouseOnKey)) chart.SetMouseOnKey(option.MouseOnKey); //是否自动更新 if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter; if (option.IsAutoUpdate!=null) chart.IsAutoUpdate=option.IsAutoUpdate; if (option.AutoUpdateFrequency>0) chart.AutoUpdateFrequency=option.AutoUpdateFrequency; //注册事件 if (option.EventCallback) { for(var i=0;i<option.EventCallback.length;++i) { var item=option.EventCallback[i]; chart.AddEventCallback(item); } } return chart; } this.SetChartBorder=function(chart, option) { if (!option.Border) return; var item=option.Border; if (IFrameSplitOperator.IsNumber(option.Border.Left)) chart.Frame.ChartBorder.Left=option.Border.Left; if (IFrameSplitOperator.IsNumber(option.Border.Right)) chart.Frame.ChartBorder.Right=option.Border.Right; if (IFrameSplitOperator.IsNumber(option.Border.Top)) chart.Frame.ChartBorder.Top=option.Border.Top; if (IFrameSplitOperator.IsNumber(option.Border.Bottom)) chart.Frame.ChartBorder.Bottom=option.Border.Bottom; var pixelTatio = GetDevicePixelRatio(); //获取设备的分辨率 chart.Frame.ChartBorder.Left*=pixelTatio; chart.Frame.ChartBorder.Right*=pixelTatio; chart.Frame.ChartBorder.Top*=pixelTatio; chart.Frame.ChartBorder.Bottom*=pixelTatio; } //事件回调 this.AddEventCallback=function(obj) { if(this.JSChartContainer && typeof(this.JSChartContainer.AddEventCallback)=='function') { JSConsole.Chart.Log('[JSStockInfoChart:AddEventCallback] obj=', obj); this.JSChartContainer.AddEventCallback(obj); } } //重新加载配置 this.ReloadResource=function(option) { if(this.JSChartContainer && typeof(this.JSChartContainer.ReloadResource)=='function') { JSConsole.Chart.Log('[JSStockInfoChart:ReloadResource] '); this.JSChartContainer.ReloadResource(option); } } this.ChartDestroy=function() { if (this.JSChartContainer && typeof (this.JSChartContainer.ChartDestroy) == 'function') { this.JSChartContainer.ChartDestroy(); } } this.Draw=function() { if(this.JSChartContainer && typeof(this.JSChartContainer.Draw)=='function') { JSConsole.Chart.Log('[JSStockInfoChart:Draw] '); this.JSChartContainer.Draw(); } } } JSStockInfoChart.Init=function(divElement) { var jsChartControl=new JSStockInfoChart(divElement); jsChartControl.OnSize(); return jsChartControl; } //自定义风格 JSStockInfoChart.SetStyle=function(option) { if (option) g_JSChartResource.SetStyle(option); } //获取颜色配置 (JSStockInfoChart.Init()之前) JSStockInfoChart.GetResource=function() { return g_JSChartResource; } JSStockInfoChart.GetfloatPrecision=function(symbol) { return GetfloatPrecision(symbol); } function JSStockInfoChartContainer(uielement) { this.ClassName='JSStockInfoChartContainer'; this.Frame; //框架画法 this.ChartPaint=[]; //图形画法 this.ChartSplashPaint=null; //等待提示 this.LoadDataSplashTitle="数据加载中"; //下载数据提示信息 this.Canvas=uielement.getContext("2d"); //画布 this.Symbol; //代码 this.NetworkFilter; //数据回调接口 this.Data= { Name:null, YClose:null, //昨收盘 YFClose:null, //昨计算价 Symbol:null, Buys: [ { Name:"买一", Price:null, Vol:null, Amount:null }, { Name:"买二", Price:null, Vol:null, Amount:null }, { Name:"买三", Price:null, Vol:null, Amount:null }, { Name:"买四", Price:null, Vol:null, Amount:null }, { Name:"买五", Price:null, Vol:null, Amount:null }, { Name:"买六", Price:null, Vol:null, Amount:null }, { Name:"买七", Price:null, Vol:null, Amount:null }, { Name:"买八", Price:null, Vol:null, Amount:null }, { Name:"买九", Price:null, Vol:null, Amount:null }, { Name:"买十", Price:null, Vol:null, Amount:null }, ], Sells: [ { Name:"卖一", Price:null, Vol:null, Amount:null }, { Name:"卖二", Price:null, Vol:null, Amount:null }, { Name:"卖三", Price:null, Vol:null, Amount:null }, { Name:"卖四", Price:null, Vol:null, Amount:null }, { Name:"卖五", Price:null, Vol:null, Amount:null }, { Name:"卖六", Price:null, Vol:null, Amount:null }, { Name:"卖七", Price:null, Vol:null, Amount:null }, { Name:"卖八", Price:null, Vol:null, Amount:null }, { Name:"卖九", Price:null, Vol:null, Amount:null }, { Name:"卖十", Price:null, Vol:null, Amount:null }, ], MapData:new Map(), //key=, { Value:, Text:, } }; //股票数据 this.BorderData={ MapData:null }; //key=Field Value:[null, {ExePrice} ,{ExePrice} ] this.MapStockData; //事件回调 this.mapEvent=new Map(); //通知外部调用 key:JSCHART_EVENT_ID value:{Callback:回调,} this.AutoUpdateTimer=null; this.AutoUpdateFrequency=15000; //15秒更新一次数据 this.UIElement=uielement; this.IsDestroy=false; //是否已经销毁了 this.ChartDestroy=function() //销毁 { this.IsDestroy=true; this.StopAutoUpdate(); } //设置事件回调 //{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.ClearData=function() { this.Data.Name=null; this.Data.YClose=null; this.Data.YFClose=null; this.Data.Buys= [ { Name:"买一", Price:null, Vol:null, Amount:null }, { Name:"买二", Price:null, Vol:null, Amount:null }, { Name:"买三", Price:null, Vol:null, Amount:null }, { Name:"买四", Price:null, Vol:null, Amount:null }, { Name:"买五", Price:null, Vol:null, Amount:null }, { Name:"买六", Price:null, Vol:null, Amount:null }, { Name:"买七", Price:null, Vol:null, Amount:null }, { Name:"买八", Price:null, Vol:null, Amount:null }, { Name:"买九", Price:null, Vol:null, Amount:null }, { Name:"买十", Price:null, Vol:null, Amount:null }, ]; this.Data.Sells= [ { Name:"卖一", Price:null, Vol:null, Amount:null }, { Name:"卖二", Price:null, Vol:null, Amount:null }, { Name:"卖三", Price:null, Vol:null, Amount:null }, { Name:"卖四", Price:null, Vol:null, Amount:null }, { Name:"卖五", Price:null, Vol:null, Amount:null }, { Name:"卖六", Price:null, Vol:null, Amount:null }, { Name:"卖七", Price:null, Vol:null, Amount:null }, { Name:"卖八", Price:null, Vol:null, Amount:null }, { Name:"卖九", Price:null, Vol:null, Amount:null }, { Name:"卖十", Price:null, Vol:null, Amount:null }, ]; this.Data.MapData=new Map(); } this.ChangeSymbol=function(symbol, option) { this.CancelAutoUpdate(); this.ClearData(); this.Symbol=symbol; this.Data.Symbol=symbol; if (option) { if (IFrameSplitOperator.IsNonEmptyArray(option.Column)) this.SetColumn(option.Column); if (IFrameSplitOperator.IsNumber(option.BuySellCount)) this.SetBuySellCount(option.BuySellCount); if (IFrameSplitOperator.IsNonEmptyArray(option.MouseOnKey)) this.SetMouseOnKey(option.MouseOnKey); } this.Draw(); this.RequestStockData(); if (this.IsAutoUpdate) { var frequency=this.AutoUpdateFrequency; setInterval(()=> { var marketStatus=MARKET_SUFFIX_NAME.GetMarketStatus(this.Symbol); if (marketStatus==0 || marketStatus==3) //闭市,盘后 return; this.RequestStockData(); }, frequency) } } this.CancelAutoUpdate=function() //关闭停止更新 { if (this.AutoUpdateTimer) { clearInterval(this.AutoUpdateTimer); this.AutoUpdateTimer = null; } } this.StopAutoUpdate=function() { this.CancelAutoUpdate(); if (!this.IsAutoUpdate) return; this.IsAutoUpdate=false; } this.RequestStockData=function() { if (this.NetworkFilter) { var obj= { Name:'JSStockInfoChartContainer::RequestStockData', //类名::函数名 Explain:'股票5档实时数据', Request: { Data:{symbol:this.Symbol} }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, (data)=> { this.RecvStockData(data); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } } this.RecvStockData=function(recv) { if (!recv) return; if (recv.name) this.Data.Name=recv.Name; if (IFrameSplitOperator.IsNumber(recv.yclose)) this.Data.YClose=recv.yclose; if (IFrameSplitOperator.IsNumber(recv.yfclose)) this.Data.YFClose=recv.yfclose; if (recv.name) this.Data.Name=recv.name; if (IFrameSplitOperator.IsNonEmptyArray(recv.data)) { for(var i=0;i<recv.data.length;++i) { var item=recv.data[i]; if (item.Name=="Buys") { if (IFrameSplitOperator.IsNonEmptyArray(item.Value)) { for(var j=0;j<item.Value.length && j<this.Data.Buys.length;++j) { var srcItem=item.Value[j]; var destItem=this.Data.Buys[j]; destItem.Price=srcItem.Price; destItem.Vol=srcItem.Vol; } } } else if (item.Name=="Sells") { if (IFrameSplitOperator.IsNonEmptyArray(item.Value)) { for(var j=0;j<item.Value.length && j<this.Data.Sells.length;++j) { var srcItem=item.Value[j]; var destItem=this.Data.Sells[j]; destItem.Price=srcItem.Price; destItem.Vol=srcItem.Vol; } } } else if (item.Name=="Symbol") { this.Data.Symbol=item.Value.Text; } else { this.Data.MapData.set(item.Name, item.Value); } } } this.Draw(); } //创建 this.Create=function(option) { this.UIElement.JSChartContainer=this; //创建框架 this.Frame=new JSStockInfoFrame(); 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; //创建表格 var chart=new ChartStockData(); chart.Frame=this.Frame; chart.ChartBorder=this.Frame.ChartBorder; chart.Canvas=this.Canvas; chart.UIElement=this.UIElement; chart.GetEventCallback=(id)=> { return this.GetEventCallback(id); } chart.Data=this.Data; chart.BorderData=this.BorderData; chart.GlobalOption=this.GlobalOption; chart.FixedRowData=this.FixedRowData; chart.SortInfo=this.SortInfo; this.ChartPaint[0]=chart; if (option) { } this.UIElement.oncontextmenu=(e)=> { this.UIOnContextMenu(e); } this.UIElement.onmousedown=(e)=> { this.UIOnMouseDown(e); } this.UIElement.onmousemove=(e)=>{ this.UIOnMouseMove(e);} this.UIElement.onmouseout=(e)=>{ this.UIOnMounseOut(e); } this.UIElement.onmouseleave=(e)=>{ this.UIOnMouseleave(e); } /* this.UIElement.ondblclick=(e)=>{ this.UIOnDblClick(e); } */ } this.UIOnMouseDown=function(e) { var pixelTatio = GetDevicePixelRatio(); this.ClickDownPoint={ X:e.clientX, Y:e.clientY }; var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio; var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio; } this.UIOnContextMenu=function(e) { if (e) //去掉系统右键菜单 { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); e.returnValue=false; } } this.UIOnMouseMove=function(e) { var pixelTatio = GetDevicePixelRatio(); var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio; var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio; var option={ Update:false }; this.OnChartMouseMove(x,y,e,option); if (option.Update===true) this.Draw(); } this.OnChartMouseMove=function(x, y, e, option) { for(var i=0;i<this.ChartPaint.length;++i) { var item=this.ChartPaint[i]; if (item && item.OnMouseMove) { if (item.OnMouseMove(x,y,e,option)) return true; } } return false; } this.UIOnMouseleave=function(e) { var option={ Update:false } this.ChartClearMouseOnData(option); if (option.Update===true) this.Draw(); } this.UIOnMounseOut=function(e) { var option={ Update:false } this.ChartClearMouseOnData(option); if (option.Update===true) this.Draw(); //this.HideAllTooltip(); } this.ChartClearMouseOnData=function(option) { for(var i=0;i<this.ChartPaint.length;++i) { var item=this.ChartPaint[i]; if (item && item.ClearMouseOnData) { item.ClearMouseOnData(option); } } } 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; //手机端需要根据分辨率比调整线段宽度 this.Frame.Draw(); this.Frame.DrawLogo(); //框架内图形 for(var i=0;i<this.ChartPaint.length;++i) { var item=this.ChartPaint[i]; item.Draw(); } } this.OnSize=function() { if (!this.Frame) return; this.SetSizeChange(true); this.Draw(); } this.SetSizeChange=function(bChanged) { for(var i=0;i<this.ChartPaint.length;++i) { var chart=this.ChartPaint[i]; if (chart) chart.SizeChange=bChanged; } } this.ReloadResource=function(option) { this.Frame.ReloadResource(option); for(var i=0;i<this.ChartPaint.length;++i) { var item=this.ChartPaint[i]; if (item.ReloadResource) item.ReloadResource(option); } if (option && (option.Redraw || option.Draw)) { this.SetSizeChange(true); this.Draw(); } } this.SetColumn=function(aryColunm, option) { var chart=this.ChartPaint[0]; if (!chart) return; chart.SetColumn(aryColunm); chart.SizeChange=true; if (option && option.Redraw) this.Draw(); } this.SetHeaderColumn=function(aryColunm, option) { var chart=this.ChartPaint[0]; if (!chart) return; chart.SetHeaderColumn(aryColunm); chart.SizeChange=true; if (option && option.Redraw) this.Draw(); } this.SetBuySellCount=function(count, option) { var chart=this.ChartPaint[0]; if (!chart) return; chart.BuySellCount=count; chart.SizeChange=true; if (option && option.Redraw) this.Draw(); } this.SetMouseOnKey=function(aryKey) { var chart=this.ChartPaint[0]; if (!chart) return; chart.SetMouseOnKey(aryKey); } } function JSStockInfoFrame() { this.ChartBorder; this.Canvas; //画布 this.BorderLine=null; //1=上 2=下 4=左 8=右 this.ClassName="JSStockInfoFrame"; this.BorderColor=g_JSChartResource.StockInfo.BorderColor; //边框线 this.LogoTextColor=g_JSChartResource.FrameLogo.TextColor; this.LogoTextFont=g_JSChartResource.FrameLogo.Font; this.ReloadResource=function(resource) { this.BorderColor=g_JSChartResource.StockInfo.BorderColor; //边框线 this.LogoTextColor=g_JSChartResource.FrameLogo.TextColor; this.LogoTextFont=g_JSChartResource.FrameLogo.Font; } this.Draw=function() { 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; if (!IFrameSplitOperator.IsNumber(this.BorderLine)) { this.Canvas.strokeStyle=this.BorderColor; this.Canvas.strokeRect(left,top,width,height); } else { this.Canvas.strokeStyle=this.BorderColor; this.Canvas.beginPath(); if ((this.BorderLine&1)>0) //上 { this.Canvas.moveTo(left,top); this.Canvas.lineTo(right,top); } if ((this.BorderLine&2)>0) //下 { this.Canvas.moveTo(left,bottom); this.Canvas.lineTo(right,bottom); } if ((this.BorderLine&4)>0) //左 { this.Canvas.moveTo(left,top); this.Canvas.lineTo(left,bottom); } if ((this.BorderLine&8)>0) //右 { this.Canvas.moveTo(right,top); this.Canvas.lineTo(right,bottom); } this.Canvas.stroke(); } } this.DrawLogo=function() { var text=g_JSChartResource.FrameLogo.Text; if (!IFrameSplitOperator.IsString(text)) return; this.Canvas.fillStyle=this.LogoTextColor; this.Canvas.font=this.LogoTextFont; this.Canvas.textAlign = 'right'; this.Canvas.textBaseline = 'bottom'; var x=this.ChartBorder.GetRight()-30; var y=this.ChartBorder.GetBottom()-5; this.Canvas.fillText(text,x,y); } } function ChartStockData() { this.Canvas; //画布 this.ChartBorder; //边框信息 this.ChartFrame; //框架画法 this.Name; //名称 this.ClassName='ChartStockData'; //类名 this.UIElement; this.GetEventCallback; //获取事件 this.Data; //数据 this.BorderData; this.SizeChange=true; this.Decimal=2; //价格小数位数 this.UpColor=g_JSChartResource.StockInfo.UpTextColor; this.DownColor=g_JSChartResource.StockInfo.DownTextColor; this.UnchangeColor=g_JSChartResource.StockInfo.UnchangeTextColor; this.HeaderConfig=CloneData(g_JSChartResource.StockInfo.Header); this.HeaderColumn= [ { Name:"现价", Key:"Price", ColorType:3, FloatPrecision:-1, DefaultText:"--.--" }, { Name:"涨幅", Key:"Increase", ColorType:1, FloatPrecision:2, StringFormat:"{Value}%", DefaultText:"--.--%" }, { Name:"涨跌", Key:"UpDown",ColorType:1, FloatPrecision:-1, DefaultText:"--.--" } ] //买卖5档配置 this.BuySellConfig=CloneData(g_JSChartResource.StockInfo.BuySell); this.BuySellCount=5; //显示几档买卖盘 this.TableConfig=CloneData(g_JSChartResource.StockInfo.Table); //显示的字段 this.Column= [ [{ Name:"涨停价", Key:"UpLimit",ColorType:3, FloatPrecision:-1 }, { Name:"跌停价", Key:"DownLimit" , ColorType:3, FloatPrecision:-1 }], [{ Name:"现价", Key:"Price", ColorType:3, FloatPrecision:-1 }, { Name:"今开", Key:"Open",ColorType:3, FloatPrecision:-1 }], [{ Name:"最高", Key:"High",ColorType:3, FloatPrecision:-1 }, { Name:"最低", Key:"Low",ColorType:3, FloatPrecision:-1 }], [{ Name:"涨幅", Key:"Increase", ColorType:1, FloatPrecision:2, StringFormat:"{Value}%" }, { Name:"涨跌", Key:"UpDown",ColorType:1, FloatPrecision:-1 }], [{ Name:"振幅", Key:"Amplitude", FloatPrecision:2, StringFormat:"{Value}%" }, { Name:"换手率", Key:"Exchange", FloatPrecision:2, StringFormat:"{Value}%" }], [{ Name:"总量", Key:"Vol", FloatPrecision:0, Format:{ Type:3, ExFloatPrecision:2 } }, { Name:"总额", Key:"Amount", FloatPrecision:0, Format:{ Type:3, ExFloatPrecision:2 } }], [{ Name:"内盘", Key:"InVol", ColorType:4, FloatPrecision:0 }, { Name:"外盘", Key:"OutVol",ColorType:5, FloatPrecision:0 }], [{ Name:"TTM", Key:"PE_TTM", FloatPrecision:2 }, { Name:"市净率", Key:"PB", FloatPrecision:2 }], [{ Name:"流通市值", Key:"FlowMarketValue", FloatPrecision:0, Format:{ Type:3, ExFloatPrecision:2 } }, { Name:"总市值", Key:"TotalMarketValue", FloatPrecision:0, Format:{ Type:3, ExFloatPrecision:2 } }], ]; this.AryCellRect=[]; this.MouseOnItem=null; //{ Key:, Rect: } //this.MouseOnItem={ Key:"SELL_PRICE_0" }; this.MouseOnConfig=CloneData(g_JSChartResource.StockInfo.MouseOn); this.MapMouseOnKey=new Map(); this.ReloadResource=function(resource) { this.UpColor=g_JSChartResource.StockInfo.UpTextColor; this.DownColor=g_JSChartResource.StockInfo.DownTextColor; this.UnchangeColor=g_JSChartResource.StockInfo.UnchangeTextColor; this.HeaderConfig=CloneData(g_JSChartResource.StockInfo.Header); //买卖5档配置 this.BuySellConfig=CloneData(g_JSChartResource.StockInfo.BuySell); this.TableConfig=CloneData(g_JSChartResource.StockInfo.Table); this.MouseOnConfig=CloneData(g_JSChartResource.StockInfo.MouseOn); } this.ClearMouseOnData=function(option) { if (!this.MouseOnItem) { this.MouseOnItem=null; if (option) option.Update=true; //需要更新 } } this.SetColumn=function(aryColumn) { this.Column=[]; if (!IFrameSplitOperator.IsNonEmptyArray(aryColumn)) return; for(var i=0;i<aryColumn.length;++i) { var item=aryColumn[i]; if (!item) continue; this.Column.push(CloneData(item)); } } this.SetHeaderColumn=function(aryColumn) { this.HeaderColumn=[]; if (!IFrameSplitOperator.IsNonEmptyArray(aryColumn)) return; for(var i=0;i<aryColumn.length;++i) { var item=aryColumn[i]; if (!item) continue; this.HeaderColumn.push(CloneData(item)); } } this.SetMouseOnKey=function(aryKey) { this.MapMouseOnKey.clear(); if (!IFrameSplitOperator.IsNonEmptyArray(aryKey)) return; for(var i=0;i<aryKey.length;++i) { var key=aryKey[i]; if (!key) continue; this.MapMouseOnKey.set(key, { Key:key }); } } this.OnMouseMove=function(x, y, e, option) { if (!IFrameSplitOperator.IsNonEmptyArray(this.AryCellRect)) return false; if (this.MouseOnItem && this.MouseOnItem.Rect) { var rect=this.MouseOnItem.Rect; if (Path2DHelper.PtInRect(x,y,rect )) return true; } for(var i=0;i<this.AryCellRect.length;++i) { var item=this.AryCellRect[i]; var rect=item.Rect; if (Path2DHelper.PtInRect(x,y, rect)) { this.MouseOnItem={ Key:item.Data.Key, Rect:rect }; if (option) option.Update=true; return true; } } if (this.MouseOnItem) { this.MouseOnItem=null; if (option) option.Update=true; } return false; } this.Draw=function() { this.AryCellRect=[]; this.Decimal=GetfloatPrecision(this.Data.Symbol); var border=this.ChartBorder.GetBorder(); var position = { Left:border.Left, Right:border.Right, Top:border.Top, Width:border.Right-border.Left, Border:border }; this.DrawHeader(position); this.DrawBuySell(position); this.DrawTable(position); } this.DrawHeader=function(position) { var config=this.HeaderConfig; var top=position.Top; var left=position.Left; var xText=left; var yText=top; this.Canvas.font=config.Name.Font; var nameHeight=this.Canvas.measureText("擎").width; nameHeight+=config.Name.Margin.Top+config.Name.Margin.Bottom; this.Canvas.font=config.Symbol.Font; var symbolHeight=this.Canvas.measureText("擎").width; symbolHeight+=config.Symbol.Margin.Top+config.Symbol.Margin.Bottom; var lineHeight=Math.max(symbolHeight, nameHeight); this.Canvas.textAlign = 'left'; this.Canvas.textBaseline = 'bottom'; if (this.Data.Name) { var text=this.Data.Name; xText+=config.Name.Margin.Left; var yBottom=yText+lineHeight-config.Name.Margin.Bottom+config.Name.Margin.YOffset; this.Canvas.font=config.Name.Font; this.Canvas.fillStyle=config.Name.Color; this.Canvas.fillText(text,xText,yBottom); var textWidth=this.Canvas.measureText(text).width; xText+=textWidth+config.Name.Margin.Right; } if (this.Data.Symbol) { var text=MARKET_SUFFIX_NAME.GetShortSymbol(this.Data.Symbol); xText+=config.Symbol.Margin.Left; var yBottom=yText+lineHeight-config.Symbol.Margin.Bottom+config.Symbol.Margin.YOffset; this.Canvas.font=config.Symbol.Font; this.Canvas.fillStyle=config.Symbol.Color; this.Canvas.fillText(text,xText,yBottom); var textWidth=this.Canvas.measureText(text).width; xText+=textWidth+config.Symbol.Margin.Right; } yText+=lineHeight; if (IFrameSplitOperator.IsNonEmptyArray(this.HeaderColumn)) { lineHeight=0; for(var i=0;i<this.HeaderColumn.length && i<config.AryCell.length;++i) { var subConfig=config.AryCell[i]; this.Canvas.font=subConfig.Font; var textHeight=this.Canvas.measureText("擎").width; textHeight+=subConfig.Margin.Top+subConfig.Margin.Bottom; if (lineHeight<textHeight) lineHeight=textHeight; } var xText=left; for(var i=0;i<this.HeaderColumn.length && i<config.AryCell.length;++i) { var item=this.HeaderColumn[i]; var text="--.--"; color=config.TextColor; if (item.DefaultText) text=item.DefaultText; var subConfig=config.AryCell[i]; if (this.Data.MapData && this.Data.MapData.has(item.Key)) { var dataItem=this.Data.MapData.get(item.Key); var text=this.FormatValue(item, dataItem); if (item.ColorType===3 && IFrameSplitOperator.IsNumber(dataItem.Value)) color=this.GetPriceColor(dataItem.Value); else if (item.ColorType==1 && IFrameSplitOperator.IsNumber(dataItem.Value)) color=this.GetUpDownColor(dataItem.Value,0); else if (item.ColorType==4) color=this.UpColor; else if (item.ColorType==5) color=this.DownColor; } if (item.TextColor) color=item.TextColor; if (text) { this.Canvas.font=subConfig.Font; var textWidth=this.Canvas.measureText(text).width; var x=xText+subConfig.Margin.Left; this.Canvas.fillStyle=color; var yBottom=yText+lineHeight-subConfig.Margin.Bottom+subConfig.Margin.YOffset; this.Canvas.fillText(text,x,yBottom); xText+=subConfig.Margin.Left+subConfig.Margin.Right+textWidth; } } yText+=lineHeight; } position.Top=yText; if (config.BottomLine && config.BottomLine.Enable) { var xLeft=position.Border.Left, xRight=position.Border.Right; this.Canvas.strokeStyle=config.BottomLine.Color; var lineWidth=1*GetDevicePixelRatio();; this.Canvas.lineWidth=lineWidth; this.Canvas.beginPath(); this.Canvas.moveTo(xLeft,ToFixedPoint(yText)); this.Canvas.lineTo(xRight,ToFixedPoint(yText)); this.Canvas.stroke(); position.Top=ToFixedPoint(yText); } } //买卖5档 this.DrawBuySell=function(position) { if (this.BuySellCount<=0) return; var config=this.BuySellConfig; var top=position.Top; var left=position.Left+config.Margin.Left; var cellWidth=(position.Width-config.Margin.Left-config.Margin.Right)/4; var yText=top+config.Margin.Top; var xText=left; this.Canvas.font=config.Font; this.Canvas.textAlign = 'left'; this.Canvas.textBaseline = 'bottom'; var cellHeight=this.Canvas.measureText("擎").width+config.CellMargin.Top+config.CellMargin.Bottom; var count=this.BuySellCount; var sellVol=0, buyVol=0; for(var i=count-1;i>=0;--i) { xText=left; var item=this.Data.Sells[i]; this.DrawBuySellItem(item, xText, yText, cellWidth, cellHeight, { Type:1, Index:i}); if (IFrameSplitOperator.IsNumber(item.Vol)) sellVol+=item.Vol; yText+=cellHeight; } var yCenter=null; if (config.CenterLine) //留出画线的位置 { yCenter=yText; var lineConfig=config.CenterLine; var lineWidth=lineConfig.Width; yText+=lineWidth; } for(var i=0;i<count && i<this.Data.Buys.length;++i) { xText=left; var item=this.Data.Buys[i]; this.DrawBuySellItem(item, xText, yText, cellWidth, cellHeight, { Type:2, Index:i}); if (IFrameSplitOperator.IsNumber(item.Vol)) buyVol+=item.Vol; yText+=cellHeight; } position.Top=yText; if (IFrameSplitOperator.IsNumber(yCenter) && config.CenterLine) { var lineConfig=config.CenterLine; var xLeft=position.Border.Left, xRight=position.Border.Right; var lineWidth=lineConfig.Width; if (buyVol+sellVol>0) { var buyRate=buyVol/(buyVol+sellVol); var barWidth=xRight-xLeft; var buyWidth=barWidth*buyRate; var xCenter=xLeft+buyWidth; this.Canvas.lineWidth=lineWidth; this.Canvas.strokeStyle=lineConfig.BuyColor; this.Canvas.beginPath(); this.Canvas.moveTo(xLeft,ToFixedPoint2(lineWidth,yCenter)); this.Canvas.lineTo(xCenter,ToFixedPoint2(lineWidth,yCenter)); this.Canvas.stroke(); this.Canvas.strokeStyle=lineConfig.SellColor; this.Canvas.beginPath(); this.Canvas.moveTo(xCenter,ToFixedPoint2(lineWidth,yCenter,)); this.Canvas.lineTo(xRight,ToFixedPoint2(lineWidth,yCenter)); this.Canvas.stroke(); } else { this.Canvas.strokeStyle=lineConfig.NoneColor; this.Canvas.lineWidth=lineWidth; this.Canvas.beginPath(); this.Canvas.moveTo(xLeft,ToFixedPoint2(lineWidth,yCenter)); this.Canvas.lineTo(xRight,ToFixedPoint2(lineWidth,yCenter)); this.Canvas.stroke(); } } if (config.BottomLine && config.BottomLine.Enable) { var xLeft=position.Border.Left, xRight=position.Border.Right; this.Canvas.strokeStyle=config.BottomLine.Color; this.Canvas.lineWidth=1*GetDevicePixelRatio(); this.Canvas.beginPath(); this.Canvas.moveTo(xLeft,ToFixedPoint(yText)); this.Canvas.lineTo(xRight,ToFixedPoint(yText)); this.Canvas.stroke(); } if (config.TopLine && config.TopLine.Enable) { var xLeft=position.Border.Left, xRight=position.Border.Right; this.Canvas.strokeStyle=config.BottomLine.Color; this.Canvas.lineWidth=1*GetDevicePixelRatio(); this.Canvas.beginPath(); this.Canvas.moveTo(xLeft,ToFixedPoint(top)); this.Canvas.lineTo(xRight,ToFixedPoint(top)); this.Canvas.stroke(); } } //itemInfo={ Type:2(1=买 2=卖), Index:数据索引 } this.DrawBuySellItem=function(item, left, top, cellWidth, cellHeight, itemInfo) { var config=this.BuySellConfig; var xText=left; var yBottom=top+cellHeight-config.CellMargin.Bottom+config.CellMargin.YOffset; if (item.Name) { this.Canvas.fillStyle=config.TitleColor; this.Canvas.fillText(item.Name,xText+config.CellMargin.Left,yBottom); } xText+=cellWidth; if (IFrameSplitOperator.IsNumber(item.Price)) { var key=`${itemInfo.Type==1?"BUY":"SELL"}_PRICE_${itemInfo.Index}`; var mouseOnItem=this.IsMouseOn(key); var text=item.Price.toFixed(this.Decimal); var textWidth=this.Canvas.measureText(text).width; var x=xText+cellWidth-textWidth-config.CellMargin.Right; var rtCell={ Left:xText, Width:cellWidth, Top:top, Height:cellHeight }; rtCell.Right=rtCell.Left+rtCell.Width; rtCell.Bottom=rtCell.Top+rtCell.Height; if (mouseOnItem) this.DrawMouseOnRect(rtCell); this.Canvas.fillStyle=this.GetPriceColor(item.Price); this.Canvas.fillText(text,x,yBottom); if (this.MapMouseOnKey.has(key)) this.AryCellRect.push({ Rect:rtCell, Data:{ Type:1, Key:key, Value:item.Price }}); } xText+=cellWidth; xText+=cellWidth; if (IFrameSplitOperator.IsNumber(item.Vol)) { var text=item.Vol.toFixed(0); var textWidth=this.Canvas.measureText(text).width; var x=xText+cellWidth-textWidth-config.CellMargin.Right; this.Canvas.fillStyle=config.VolColor; this.Canvas.fillText(text,x,yBottom); } } this.IsMouseOn=function(key) { if (!this.MouseOnItem) return null; if (this.MouseOnItem.Key===key) return this.MouseOnItem; return null; } this.DrawMouseOnRect=function(rect) { if (!this.MouseOnItem) return; this.Canvas.fillStyle=this.MouseOnConfig.BGColor; this.Canvas.fillRect(rect.Left, rect.Top, rect.Width, rect.Height); this.MouseOnItem.Rect=rect; } this.DrawTable=function(position) { if (!IFrameSplitOperator.IsNonEmptyArray(this.Column)) return; var config=this.TableConfig; var top=position.Top; var left=position.Left+config.Margin.Left; var cellWidth=(position.Width-config.Margin.Left-config.Margin.Right)/4; var yText=top+config.Margin.Top; var xText=left; this.Canvas.font=config.Font; this.Canvas.textAlign = 'left'; this.Canvas.textBaseline = 'bottom'; var cellHeight=this.Canvas.measureText("擎").width+config.CellMargin.Top+config.CellMargin.Bottom; for(var i=0;i<this.Column.length;++i) { xText=left; var item=this.Column[i]; if (!item || !IFrameSplitOperator.IsNonEmptyArray(item)) continue; this.DrawRowItem(item, xText, yText, cellWidth, cellHeight); yText+=cellHeight; } } this.DrawRowItem=function(aryData, left, top, cellWidth, cellHeight) { var config=this.TableConfig; var xText=left; var yBottom=top+cellHeight-config.CellMargin.Bottom+config.CellMargin.YOffset; for(var i=0;i<aryData.length && i<2;++i) { var item=aryData[i]; if (item) { if (item.Name) { this.Canvas.fillStyle=config.TitleColor; this.Canvas.fillText(item.Name,xText+config.CellMargin.Left,yBottom); } xText+=cellWidth; if (this.Data.MapData && this.Data.MapData.has(item.Key)) { var dataItem=this.Data.MapData.get(item.Key); color=config.TextColor; var text=this.FormatValue(item, dataItem); if (item.ColorType===3 && IFrameSplitOperator.IsNumber(dataItem.Value)) color=this.GetPriceColor(dataItem.Value); else if (item.ColorType==1 && IFrameSplitOperator.IsNumber(dataItem.Value)) color=this.GetUpDownColor(dataItem.Value,0); else if (item.ColorType==4) color=this.UpColor; else if (item.ColorType==5) color=this.DownColor; if (item.TextColor) color=item.TextColor; if (text) { if (i==0 && item.ShowType==1) //整行显示 { var mouseOnItem=this.IsMouseOn(item.Key); var textWidth=this.Canvas.measureText(text).width; var x=xText+(cellWidth*3)-textWidth-config.CellMargin.Right; var rtCell={ Left:xText+cellWidth, Top:top, Width:cellWidth*2, Height:cellHeight}; rtCell.Right=rtCell.Left+rtCell.Width; rtCell.Bottom=rtCell.Top+rtCell.Height; if (mouseOnItem) this.DrawMouseOnRect(rtCell); this.Canvas.fillStyle=color; this.Canvas.fillText(text,x,yBottom); if (this.MapMouseOnKey.has(item.Key)) this.AryCellRect.push({ Rect:rtCell, Data:{ Type:2, Key:item.Key, Value:dataItem }}); break; } else { var mouseOnItem=this.IsMouseOn(item.Key); var textWidth=this.Canvas.measureText(text).width; var x=xText+cellWidth-textWidth-config.CellMargin.Right; var rtCell={ Left:xText, Top:top, Width:cellWidth, Height:cellHeight}; rtCell.Right=rtCell.Left+rtCell.Width; rtCell.Bottom=rtCell.Top+rtCell.Height; if (mouseOnItem) this.DrawMouseOnRect(rtCell); this.Canvas.fillStyle=color; this.Canvas.fillText(text,x,yBottom); if (this.MapMouseOnKey.has(item.Key)) this.AryCellRect.push({ Rect:rtCell, Data:{ Type:2, Key:item.Key, Value:dataItem }}); } } } xText+=cellWidth; } else { xText+=cellWidth+cellWidth; } } } this.FormatValue=function(column, data) { var dec=0; //小数位数 if (IFrameSplitOperator.IsNumber(column.FloatPrecision)) { if (column.FloatPrecision===-1) dec=this.Decimal; else dec=column.FloatPrecision; } var text=null; if (!data) return text; if (data.Text) { text=data.Text; } else if (IFrameSplitOperator.IsNumber(data.Value)) { var value=data.Value; text=value.toFixed(dec); //格式化 if (column.Format && IFrameSplitOperator.IsNumber(column.Format.Type)) { var format=column.Format; switch(format.Type) { case 1: //原始数据 text=value.toFixed(dec); break; case 2: //千分位分割 text=IFrameSplitOperator.FormatValueThousandsString(value, dec); break; case 3: var exfloatPrecision=1; if (IFrameSplitOperator.IsNumber(format.ExFloatPrecision)) exfloatPrecision=format.ExFloatPrecision; text=IFrameSplitOperator.FormatValueStringV2(value, dec,exfloatPrecision); break; } } } if (column.StringFormat && text) text=column.StringFormat.replace('{Value}',text); return text; } this.GetPriceColor=function(price) { var upperSymbol=null; if (this.Data.Symbol) upperSymbol=this.Data.Symbol.toUpperCase(); if (MARKET_SUFFIX_NAME.IsChinaFutures(upperSymbol)) { if (!IFrameSplitOperator.IsNumber(this.Data.YFClose)) return this.UnchangeColor; return this.GetUpDownColor(price, this.Data.YFClose); } else { if (!IFrameSplitOperator.IsNumber(this.Data.YClose)) return this.UnchangeColor; return this.GetUpDownColor(price, this.Data.YClose); } } this.GetUpDownColor=function(price, price2) { if (price>price2) return this.UpColor; else if (price<price2) return this.DownColor; else return this.UnchangeColor; } }