UNPKG

hqchart

Version:

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

1,453 lines (1,198 loc) 127 kB
/* Copyright (c) 2018 jones http://www.apache.org/licenses/LICENSE-2.0 开源项目 https://github.com/jones2000/HQChart jones_2000@163.com 封装T型报价列表控件 (H5版本) 不提供内置测试数据 */ function JSTReportChart(divElement) { this.DivElement=divElement; this.JSChartContainer; //表格控件 this.ResizeListener; //大小变动监听 //h5 canvas this.CanvasElement=document.createElement("canvas"); this.CanvasElement.className='jstreport-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("[JSTReportChart::JSReportChart] 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(`[JSTReportChart::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.CreateJSTReportChartContainer(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.MinuteChartTooltip && option.MinuteChartTooltip.Enable) chart.InitalMinuteChartTooltip(option.MinuteChartTooltip); //分时图 if (option.FloatTooltip && option.FloatTooltip.Enable) chart.InitalFloatTooltip(option.FloatTooltip); //提示信息 if (option.Symbol) { chart.Draw(); var name=option.Symbol; if (option.Name) name=option.Name; chart.ChangeSymbol(option.Symbol, {Name:name}); //下载列表码表 } } this.CreateJSTReportChartContainer=function(option) { var chart=new JSTReportChartContainer(this.CanvasElement); chart.Create(option); if (option.NetworkFilter) chart.NetworkFilter=option.NetworkFilter; if (IFrameSplitOperator.IsNonEmptyArray(option.Column)) chart.SetColumn(option.Column); if (IFrameSplitOperator.IsNonEmptyArray(option.Tab)) chart.SetTab(option.Tab); if (IFrameSplitOperator.IsNumber(option.TabSelected)) chart.SetSelectedTab(option.TabSelected); if (IFrameSplitOperator.IsBool(option.EnableDragRow)) chart.EnableDragRow=option.EnableDragRow; if (IFrameSplitOperator.IsNumber(option.DragRowType)) chart.DragRowType=option.DragRowType; if (IFrameSplitOperator.IsBool(option.EnableDragHeader)) chart.EnableDragHeader=option.EnableDragHeader; if (IFrameSplitOperator.IsBool(option.EnablePageCycle)) chart.EnablePageCycle=option.EnablePageCycle; if (IFrameSplitOperator.IsNumber(option.FixedRowCount)) chart.SetFixedRowCount(option.FixedRowCount); //固定行 if (option.SortInfo) { var item=option.SortInfo; if (IFrameSplitOperator.IsNumber(item.Field)) chart.SortInfo.Field=item.Field; if (IFrameSplitOperator.IsNumber(item.Sort)) chart.SortInfo.Sort=item.Sort; } this.SetChartBorder(chart, option); //是否自动更新 if (option.IsAutoUpdate!=null) chart.IsAutoUpdate=option.IsAutoUpdate; if (option.AutoUpdateFrequency>0) chart.AutoUpdateFrequency=option.AutoUpdateFrequency; if (IFrameSplitOperator.IsBool(option.EnableFilter)) chart.EnableFilter=option.EnableFilter; //注册事件 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.CreateResizeListener=function() { this.ResizeListener = new ResizeObserver((entries)=>{ this.OnDivResize(entries); }); this.ResizeListener.observe(this.DivElement); } this.OnDivResize=function(entries) { JSConsole.Chart.Log("[JSTReportChart::OnDivResize] entries=", entries); this.OnSize(); } ///////////////////////////////////////////////////////////////////////////// //对外接口 //切换股票代码接口 this.ChangeSymbol=function(symbol, option) { if (this.JSChartContainer) this.JSChartContainer.ChangeSymbol(symbol,option); } this.SetColumn=function(aryColumn, option) { if (this.JSChartContainer) this.JSChartContainer.SetColumn(aryColumn,option); } //事件回调 this.AddEventCallback=function(obj) { if(this.JSChartContainer && typeof(this.JSChartContainer.AddEventCallback)=='function') { JSConsole.Chart.Log('[JSTReportChart:AddEventCallback] obj=', obj); this.JSChartContainer.AddEventCallback(obj); } } //重新加载配置 this.ReloadResource=function(option) { if(this.JSChartContainer && typeof(this.JSChartContainer.ReloadResource)=='function') { JSConsole.Chart.Log('[JSTReportChart: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('[JSTReportChart:Draw] '); this.JSChartContainer.Draw(); } } } JSTReportChart.Init=function(divElement) { var jsChartControl=new JSTReportChart(divElement); jsChartControl.OnSize(); return jsChartControl; } //自定义风格 JSTReportChart.SetStyle=function(option) { if (option) g_JSChartResource.SetStyle(option); } //获取颜色配置 (设置配必须啊在JSChart.Init()之前) JSTReportChart.GetResource=function() { return g_JSChartResource; } JSTReportChart.GetfloatPrecision=function(symbol) { return GetfloatPrecision(symbol); } function HQTReportItem() { this.Symbol; this.Name; this.YClose; this.Open; this.Price; this.High; this.Low; this.Amount; this.Vol; this.Positon; //持仓量 this.Increase; //涨幅 this.UpDown; //涨跌 this.Exchange; //换手 this.Amplitude; //振幅 this.BuyPrice; //买价/量 this.BuyVol; this.SellPrice; //卖价/量 this.SellVol; this.AvPrice; //均价 this.LimitHigh; //涨停价 this.LimitLow; //跌停价 this.CloseLine; //{Data:[], Max:, Min:, Count: } this.ExtendData; //扩展数据 } function JSTReportChartContainer(uielement) { this.ClassName='JSTReportChartContainer'; this.Frame; //框架画法 this.ChartPaint=[]; //图形画法 this.ChartSplashPaint=null; //等待提示 this.LoadDataSplashTitle="数据加载中"; //下载数据提示信息 this.SplashTitle={ StockList:"下载码表中....." } ; this.Canvas=uielement.getContext("2d"); //画布 this.Tooltip=document.createElement("div"); this.Tooltip.className='jstreport-tooltip'; this.Tooltip.style.background=g_JSChartResource.TooltipBGColor; this.Tooltip.style.opacity=g_JSChartResource.TooltipAlpha; this.Tooltip.style["pointer-events"]="none"; this.Tooltip.id=Guid(); uielement.parentNode.appendChild(this.Tooltip); this.Symbol; //期权对应的品种代码 this.Name; //期权对应的品种名称 this.NetworkFilter; //数据回调接口 this.Data={ XOffset:0, YOffset:0, Data:[], Price:null, MatchExePrice:null }; //股票列表 Price=标的物市场价格 MatchExePrice=标的物市场价格匹配的行权价格 this.BorderData={ MapData:null }; //key=Field Value:[null, {ExePrice} ,{ExePrice} ] this.SourceData={ Data:[] } ; //原始股票顺序(排序还原用) {ExePrice=行权价格 LeftData:, RightData} this.FixedRowData={ Data:[] }; //[ { TData:{ LeftData:[], RightData:[] }} , ...]; 顶部固定行Data:[{ Value:, Text:, Color:, TextAgiln: }] this.DelayUpdateTimer=null; //延迟更新 this.DelayUpdateFrequency=500; //延迟更新时间 this.MapStockData; this.MapExePriceData; this.FlashBG=new Map(); this.FlashBGTimer=null; //闪烁背景 Value:{ LastTime:数据最后的时间, Data: { Key:ID, BGColor:, Time: , Count: 次数 } }; this.GlobalOption={ FlashBGCount:0 } this.SortInfo={ Field:-1, Sort:0 }; //排序信息 {Field:排序字段id, Sort:0 不排序 1升序 2降序 } //事件回调 this.mapEvent=new Map(); //通知外部调用 key:JSCHART_EVENT_ID value:{Callback:回调,} this.AutoUpdateTimer=null; this.AutoUpdateFrequency=15000; //15秒更新一次数据 this.UIElement=uielement; this.LastPoint=new Point(); //鼠标位置 this.IsOnTouch=false; this.TouchDrag; this.TouchMoveMinAngle=70; //左右移动最小角度 this.YStepPixel=5*GetDevicePixelRatio(); this.XStepPixel=10*GetDevicePixelRatio(); //拖拽滚动条 this.DragXScroll=null; //{Start:{x,y}, End:{x, y}} this.EnablePageCycle=false; //是否循环翻页 this.TooltipMinuteChart; //分时图 this.FloatTooltip; //浮框提示 this.LastMouseStatus={ MoveStatus:null, TooltipStatus:null, MouseOnStatus:null }; this.IsDestroy=false; //是否已经销毁了 this.ChartDestroy=function() //销毁 { this.IsDestroy=true; this.StopAutoUpdate(); this.DestroyMinuteChartTooltip(); this.DestroyFloatTooltip(); } this.InitalMinuteChartTooltip=function(option) { if (this.TooltipMinuteChart) return; this.TooltipMinuteChart=new JSTooltipMinuteChart(); this.TooltipMinuteChart.Inital(this, option); this.TooltipMinuteChart.Create(); } this.DestroyMinuteChartTooltip=function() { if (!this.TooltipMinuteChart) return; this.TooltipMinuteChart.Destroy(); this.TooltipMinuteChart=null; } //data={ Symbol } this.ShowMinuteChartTooltip=function(x,y, data) { if (!this.TooltipMinuteChart) return; var rtClient=this.UIElement.getBoundingClientRect(); var rtScroll=GetScrollPosition(); var offsetLeft=rtClient.left+rtScroll.Left; var offsetTop=rtClient.top+rtScroll.Top; data.Offset={ Left:offsetLeft, Top:offsetTop }; this.TooltipMinuteChart.Show(data, x,y); } this.HideMinuteChartTooltip=function() { if (!this.TooltipMinuteChart) return; this.TooltipMinuteChart.Hide(); } this.InitalFloatTooltip=function(option) { if (this.FloatTooltip) return; this.FloatTooltip=new JSFloatTooltip(); this.FloatTooltip.Inital(this, option); this.FloatTooltip.Create(); } this.HideFloatTooltip=function() { if (!this.FloatTooltip) return; this.FloatTooltip.Hide(); } this.DestroyFloatTooltip=function() { if (!this.FloatTooltip) return; this.FloatTooltip.Destroy(); this.FloatTooltip=null; } this.DrawFloatTooltip=function(point,toolTip) { if (!this.FloatTooltip) return; this.UpdateFloatTooltip(point, toolTip) } this.UpdateFloatTooltip=function(point, toolTip) { if (!this.FloatTooltip) return; var sendData= { Tooltip:toolTip, Point:point, DataType:4, }; this.FloatTooltip.Update(sendData); } //清空固定行数据 this.ClearFixedRowData=function() { this.FixedRowData.Data=[]; } //设置固定行 this.SetFixedRowCount=function(value) { var chart=this.ChartPaint[0]; if (!chart) return; chart.FixedRowCount=value; } //创建 this.Create=function(option) { this.UIElement.JSChartContainer=this; //创建等待提示 this.ChartSplashPaint = new ChartSplashPaint(); this.ChartSplashPaint.Canvas = this.Canvas; this.ChartSplashPaint.SetTitle(this.LoadDataSplashTitle); this.ChartSplashPaint.IsEnableSplash=true; //创建框架 this.Frame=new JSTReportFrame(); this.Frame.ChartBorder=new ChartBorder(); this.Frame.ChartBorder.UIElement=this.UIElement; this.Frame.ChartBorder.Top=30; this.Frame.ChartBorder.Left=5; this.Frame.ChartBorder.Bottom=20; this.Frame.Canvas=this.Canvas; this.ChartSplashPaint.Frame = this.Frame; //创建表格 var chart=new ChartTReport(); 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.GetExePriceDataCallback=(exePrice)=>{ return this.GetExePriceData(exePrice);} chart.GetFlashBGDataCallback=(symbol, time)=>{ return this.GetFlashBGData(symbol, time); } 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) { if (IFrameSplitOperator.IsBool(option.IsShowHeader)) chart.IsShowHeader=option.IsShowHeader; //是否显示表头 if (IFrameSplitOperator.IsNumber(option.FixedColumn)) chart.FixedColumn=option.FixedColumn; //固定列 if (IFrameSplitOperator.IsNumber(option.BorderLine)) this.Frame.BorderLine=option.BorderLine; //边框 if (IFrameSplitOperator.IsBool(option.ItemBorder)) chart.IsDrawBorder=option.ItemBorder; //单元格边框 if (IFrameSplitOperator.IsNumber(option.SelectedModel)) chart.SelectedModel=option.SelectedModel; } var bRegisterKeydown=true; var bRegisterWheel=true; if (option) { if (option.KeyDown===false) { bRegisterKeydown=false; JSConsole.Chart.Log('[JSTReportChartContainer::Create] not register keydown event.'); } if (option.Wheel===false) { bRegisterWheel=false; JSConsole.Chart.Log('[JSTReportChartContainer::Create] not register wheel event.'); } } if (bRegisterKeydown) this.UIElement.addEventListener("keydown", (e)=>{ this.OnKeyDown(e); }, true); //键盘消息 if (bRegisterWheel) this.UIElement.addEventListener("wheel", (e)=>{ this.OnWheel(e); }, true); //上下滚动消息 this.UIElement.ondblclick=(e)=>{ this.UIOnDblClick(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.oncontextmenu=(e)=> { this.UIOnContextMenu(e); } /* this.UIElement.onmouseup=(e)=>{ this.UIOnMounseUp(e); } //手机拖拽 this.UIElement.ontouchstart=(e)=> { this.OnTouchStart(e); } this.UIElement.ontouchmove=(e)=> {this.OnTouchMove(e); } this.UIElement.ontouchend=(e)=> {this.OnTouchEnd(e); } */ } 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.LastMouseStatus.MouseOnStatus=null; if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash) { this.Frame.Draw( { IsEnableSplash:this.ChartSplashPaint.IsEnableSplash} ); this.ChartSplashPaint.Draw(); return; } this.Frame.Draw(); this.Frame.DrawLogo(); //框架内图形 for(var i=0;i<this.ChartPaint.length;++i) { var item=this.ChartPaint[i]; if (item.IsDrawFirst) item.Draw(); } for(var i=0; i<this.ChartPaint.length; ++i) { var item=this.ChartPaint[i]; if (!item.IsDrawFirst) item.Draw(); } if (this.GlobalOption.FlashBGCount>0) { this.DelayDraw(500); } } this.DelayDraw=function(frequency) { if (typeof (this.FlashBGTimer) == 'number') { clearTimeout(this.FlashBGTimer); this.FlashBGTimer = null; } this.FlashBGTimer=setTimeout(()=> { this.Draw(); },frequency); } this.ClearData=function() { this.SourceData.Data=[]; this.Data.Data=[]; this.Data.Price=null; this.Data.XOffset=0; //清空偏移 this.Data.YOffset=0; this.MapStockData=new Map(); this.MapExePriceData=null; this.BorderData.MapData=null; } this.StopAutoUpdate=function() { this.CancelAutoUpdate(); this.AutoUpdateEvent(false,'JSTReportChartContainer::StopAutoUpdate'); if (!this.IsAutoUpdate) return; this.IsAutoUpdate=false; } //设置事件回调 //{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.OnSize=function() { if (!this.Frame) return; this.SetSizeChange(true); this.Draw(); this.DelayUpdateStockData(); } this.SetSizeChange=function(bChanged) { for(var i=0;i<this.ChartPaint.length;++i) { var chart=this.ChartPaint[i]; if (chart) chart.SizeChange=bChanged; } } this.ChangeSymbol=function(symbol, option) { this.CancelAutoUpdate(); this.ClearData(); this.Symbol=symbol; this.Name=symbol; if (option) { if (option.Name) this.Name=option.Name; } this.RequestStockListData(); } this.CancelAutoUpdate=function() //关闭停止更新 { if (typeof (this.AutoUpdateTimer) == 'number') { clearTimeout(this.AutoUpdateTimer); this.AutoUpdateTimer = null; } } 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.RequestStockListData=function() { this.ChartSplashPaint.SetTitle(this.SplashTitle.StockList); this.ChartSplashPaint.EnableSplash(true); this.Draw(); var self=this; if (this.NetworkFilter) { var obj= { Name:'JSTReportChartContainer::RequestStockListData', //类名:: Explain:'T型报价列表数据', Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { if (!data) return; if (data.symbol!=self.Symbol) return; self.ChartSplashPaint.EnableSplash(false); self.RecvStockListData(data); }); if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求 } throw { Name:'JSTReportChartContainer::RequestStockListData', Error:'(T型报价列表数据)不提供内置测试数据' }; } this.RecvStockListData=function(data) { this.MapExePriceData=new Map(); this.MapStockData=new Map(); if (IFrameSplitOperator.IsNonEmptyArray(data.data)) { //0=行权价格 1=左边期权代码 2=右侧期权代码 3=左侧期权名称 4=右侧期权名称 for(var i=0;i<data.data.length;++i) { var item=data.data[i]; var exePrice=item[0]; var leftData=new HQTReportItem(); leftData.Symbol=leftData.Name=item[1]; if (item[3]) leftData.Name=item[3]; var rightData=new HQTReportItem(); rightData.Symbol=rightData.Name=item[2]; if (item[4]) rightData.Name=item[4]; this.MapStockData.set(leftData.Symbol, leftData); this.MapStockData.set(rightData.Symbol, rightData); var dataItem={ ExePrice:exePrice, LeftData:leftData, RightData:rightData }; this.MapExePriceData.set(dataItem.ExePrice, dataItem); this.SourceData.Data.push(exePrice); this.Data.Data.push(exePrice); } } if (IFrameSplitOperator.IsNumber(data.price)) { this.Data.Price=data.price; } if ( IFrameSplitOperator.IsNumber(data.Decimal)) { var chart=this.ChartPaint[0]; if (chart) chart.DefaultDecimal=data.Decimal; } this.Draw(); this.UpdateStockData(); } this.GetExePriceData=function(exePrice) { if (!this.MapExePriceData) return null; if (!this.MapExePriceData.has(exePrice)) return null; return this.MapExePriceData.get(exePrice); } this.UpdateStockData=function() { if (!IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return; if (this.MapStockData.size<=0) return; var arySymbol=[]; for(var mapItem of this.MapStockData) { arySymbol.push(mapItem[0]); } if (!IFrameSplitOperator.IsNonEmptyArray(arySymbol)) return; this.RequestStockData(arySymbol); } //下载期权数据 this.RequestStockData=function(arySymbol) { var self=this; if (this.NetworkFilter) { var chart=this.ChartPaint[0]; var obj= { Name:'JSTReportChartContainer::RequestStockData', //类名::函数名 Explain:'T型报价列表期权数据', Request:{ Data: { stocks: arySymbol, symbol:this.Symbol, fixedRowCount:chart.FixedRowCount } }, Self:this, PreventDefault:false }; this.NetworkFilter(obj, function(data) { self.RecvStockData(data); self.AutoUpdate(); }); if (obj.PreventDefault==true) return; } throw { Name:'JSTReportChartContainer::RequestStockData', Error:'(T型报价列表期权数据)不提供内置测试数据' }; } this.RecvStockData=function(data) { var setUpdateSymbol=new Set(); //更新的股票列表 if (IFrameSplitOperator.IsNonEmptyArray(data.data)) { for(var i=0;i<data.data.length;++i) { var item=data.data[i]; var symbol=item[0]; //0=证券代码; if (!symbol) continue; var stock=null; if (this.MapStockData.has(symbol)) { stock=this.MapStockData.get(symbol); } else { stock=new HQTReportItem(); stock.Symbol=symbol; this.MapStockData.set(symbol, stock); } this.ReadStockJsonData(stock, item); if (!setUpdateSymbol.has(symbol)) setUpdateSymbol.add(symbol); } } if (IFrameSplitOperator.IsNumber(data.price)) { this.Data.Price=data.price; this.Data.MatchExePrice=null; } if (IFrameSplitOperator.IsNonEmptyArray(data.fixedRowData)) { for(var i=0;i<data.fixedRowData.length;++i) { var item=data.fixedRowData[i]; if (!item || !item.TData) continue; this.FixedRowData.Data[i]=item; } } var chart=this.ChartPaint[0]; //实时数据排序 if (chart && (this.SortInfo.Sort==1 || this.SortInfo.Sort==2 ) && IFrameSplitOperator.IsNumber(this.SortInfo.Field) && this.SortInfo.Field>=0) { var column=chart.Column[this.SortInfo.Field]; var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_TREPORT_LOCAL_SORT); if (event && event.Callback) { var sendData={ Column:column, SortInfo:this.SortInfo, SymbolList:this.Data.Data, Result:null }; event.Callback (event, sendData, this); if (Array.isArray(sendData.Result)) this.Data.Data=sendData.Result; } else { this.Data.Data.sort((left, right)=> { return this.LocalSort(left, right, column, this.SortInfo.Sort, this.SortInfo.CellType); }); } } this.CalculateData(); this.Draw(); } //计算统计数据 this.CalculateData=function() { this.Data.MatchExePrice=null; if (!this.MapExePriceData || this.MapExePriceData.size<=0) return; var leftMaxPosition={ Max:null, ExePrice:null, CellType:1 }; var rightMaxPosition={ Max:null,ExePrice:null, CellType:2 }; this.BorderData.MapData=new Map(); var aryPrice=[]; for(var mapItem of this.MapExePriceData) { var item=mapItem[1]; var leftData=item.LeftData; var rightData=item.RightData; if (leftData && IFrameSplitOperator.IsNumber(leftData.Position)) { if (leftMaxPosition.Max==null || leftMaxPosition.Max<leftData.Position) { leftMaxPosition.Max=leftData.Position; leftMaxPosition.ExePrice=mapItem[0]; } } if (rightData && IFrameSplitOperator.IsNumber(rightData.Position)) { if (rightMaxPosition.Max==null || rightMaxPosition.Max<rightData.Position) { rightMaxPosition.Max=rightData.Position; rightMaxPosition.ExePrice=mapItem[0]; } } aryPrice.push(item.ExePrice); } var aryData=[null, null, null]; if (leftMaxPosition.ExePrice) aryData[1]=leftMaxPosition; if (rightMaxPosition.ExePrice) aryData[2]=rightMaxPosition; this.BorderData.MapData.set(TREPORT_COLUMN_ID.POSITION_ID, { Data:aryData }); if (IFrameSplitOperator.IsNumber(this.Data.Price)) { aryPrice.sort((left, right)=>{ return left-right;}); var prePrice=null; for(var i=0;i<aryPrice.length;++i) { var value=aryPrice[i]; if (value>this.Data.Price) { this.Data.MatchExePrice=prePrice break; } prePrice=value; } } } //读取单条股票json数据 this.ReadStockJsonData=function(stock, item) { //0=证券代码 1=股票名称 2=昨收 3=开 4=高 5=低 6=收 7=成交量 8=成交金额, 9=买价 10=买量 11=卖价 12=卖量 13=均价 14=持仓 16=涨停价 17=跌停价 //21=涨幅% 22=涨跌 24=振幅% //30=全局扩展数据 31=当前板块扩展数据 // 101-110 数值 if (IFrameSplitOperator.IsString(item[1])) stock.Name=item[1]; if (IFrameSplitOperator.IsNumber(item[2])) stock.YClose=item[2]; if (IFrameSplitOperator.IsNumber(item[3])) stock.Open=item[3]; if (IFrameSplitOperator.IsNumber(item[4])) stock.High=item[4]; if (IFrameSplitOperator.IsNumber(item[5])) stock.Low=item[5]; if (IFrameSplitOperator.IsNumber(item[6])) stock.Price=item[6]; if (IFrameSplitOperator.IsNumber(item[7])) stock.Vol=item[7]; if (IFrameSplitOperator.IsNumber(item[8])) stock.Amount=item[8]; if (IFrameSplitOperator.IsNumber(item[9])) stock.BuyPrice=item[9]; if (IFrameSplitOperator.IsNumber(item[10])) stock.BuyVol=item[10]; if (IFrameSplitOperator.IsNumber(item[11])) stock.SellPrice=item[11]; if (IFrameSplitOperator.IsNumber(item[12])) stock.SellVol=item[12]; if (IFrameSplitOperator.IsNumber(item[13])) stock.AvPrice=item[13]; //均价 if (IFrameSplitOperator.IsNumber(item[14])) stock.Position=item[14]; //持仓 if (IFrameSplitOperator.IsNumber(item[16])) stock.LimitHigh=item[16]; //涨停价 if (IFrameSplitOperator.IsNumber(item[17])) stock.LimitLow=item[17]; //跌停价 if (IFrameSplitOperator.IsNumber(item[21])) stock.Increase=item[21]; //涨幅% if (IFrameSplitOperator.IsNumber(item[22])) stock.UpDown=item[22]; //涨跌 if (IFrameSplitOperator.IsNumber(item[24])) stock.Amplitude=item[24]; //振幅% if (item[27]) stock.NameEx=item[27]; //扩展名字 //衍生数据计算 if (!IFrameSplitOperator.IsNumber(item[21])) //涨幅% { if (IFrameSplitOperator.IsNumber(stock.Price) && IFrameSplitOperator.IsNumber(stock.YClose) && stock.YClose!=0) stock.Increase=(stock.Price-stock.YClose)/stock.YClose*100; } if (!IFrameSplitOperator.IsNumber(item[22])) //涨跌 { if (IFrameSplitOperator.IsNumber(stock.Price) && IFrameSplitOperator.IsNumber(stock.YClose)) stock.UpDown=stock.Price-stock.YClose; } if (!IFrameSplitOperator.IsNumber(item[24])) //振幅% { if (IFrameSplitOperator.IsNumber(stock.High) && IFrameSplitOperator.IsNumber(stock.Low) && IFrameSplitOperator.IsNumber(stock.YClose) && stock.YClose!=0) stock.Amplitude=(stock.High-stock.Low)/stock.YClose*100; } if (item[30]) stock.ExtendData=item[30]; //30=全局扩展数据 if (item[32]) stock.CloseLine=item[32]; //32=收盘价线 if (item[33]) stock.KLine=item[33]; //33=K线 if (item[34]) stock.ExePrice=item[34]; //34=行权价设置 { BGColor:背景色, Text:, TextColor } //10个数值型 101-199 if (IFrameSplitOperator.IsNumber(item[101])) stock.ReserveNumber1=item[101]; if (IFrameSplitOperator.IsNumber(item[102])) stock.ReserveNumber2=item[102]; if (IFrameSplitOperator.IsNumber(item[103])) stock.ReserveNumber3=item[103]; if (IFrameSplitOperator.IsNumber(item[104])) stock.ReserveNumber4=item[104]; if (IFrameSplitOperator.IsNumber(item[105])) stock.ReserveNumber5=item[105]; if (IFrameSplitOperator.IsNumber(item[106])) stock.ReserveNumber6=item[106]; if (IFrameSplitOperator.IsNumber(item[107])) stock.ReserveNumber7=item[107]; if (IFrameSplitOperator.IsNumber(item[108])) stock.ReserveNumber8=item[108]; if (IFrameSplitOperator.IsNumber(item[109])) stock.ReserveNumber9=item[109]; if (IFrameSplitOperator.IsNumber(item[110])) stock.ReserveNumber10=item[110]; //10个字符型 201-299 if (IFrameSplitOperator.IsString(item[201]) || IFrameSplitOperator.IsObject(item[201])) stock.ReserveString1=item[201]; if (IFrameSplitOperator.IsString(item[202]) || IFrameSplitOperator.IsObject(item[202])) stock.ReserveString2=item[202]; if (IFrameSplitOperator.IsString(item[203]) || IFrameSplitOperator.IsObject(item[203])) stock.ReserveString3=item[203]; if (IFrameSplitOperator.IsString(item[204]) || IFrameSplitOperator.IsObject(item[204])) stock.ReserveString4=item[204]; if (IFrameSplitOperator.IsString(item[205]) || IFrameSplitOperator.IsObject(item[205])) stock.ReserveString5=item[205]; if (IFrameSplitOperator.IsString(item[206]) || IFrameSplitOperator.IsObject(item[206])) stock.ReserveString6=item[206]; if (IFrameSplitOperator.IsString(item[207]) || IFrameSplitOperator.IsObject(item[207])) stock.ReserveString7=item[207]; if (IFrameSplitOperator.IsString(item[208]) || IFrameSplitOperator.IsObject(item[208])) stock.ReserveString8=item[208]; if (IFrameSplitOperator.IsString(item[209]) || IFrameSplitOperator.IsObject(item[209])) stock.ReserveString9=item[209]; if (IFrameSplitOperator.IsString(item[210]) || IFrameSplitOperator.IsObject(item[210])) stock.ReserveString10=item[210]; } this.AutoUpdate=function(waitTime) //waitTime 更新时间 { this.CancelAutoUpdate(); if (!this.IsAutoUpdate) return; var self = this; var marketStatus=2; var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_TREPORT_MARKET_STATUS); if (event && event.Callback) { var sendData={ MarketStatus:2 }; event.Callback(event, sendData, this); if (IFrameSplitOperator.IsNumber(sendData.MarketStatus)) marketStatus=sendData.MarketStatus; } 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.UpdateStockData(); },frequency); } } //delay=是否延迟 this.DelayUpdateStockData=function() { if (this.DelayUpdateTimer!=null) { clearTimeout(this.DelayUpdateTimer); this.DelayUpdateTimer = null; } var frequency=this.DelayUpdateFrequency; this.DelayUpdateTimer=setTimeout(()=> { this.UpdateStockData(); },frequency); } this.UIOnDblClick=function(e) { var pixelTatio = GetDevicePixelRatio(); var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio; var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio; var chart=this.GetTReportChart(); if (chart) chart.OnDblClick(x,y,e); } this.UIOnMouseDown=function(e) { var pixelTatio = GetDevicePixelRatio(); var x = (e.clientX-this.UIElement.getBoundingClientRect().left)*pixelTatio; var y = (e.clientY-this.UIElement.getBoundingClientRect().top)*pixelTatio; var chart=this.ChartPaint[0]; if (!chart) return; var clickData=chart.OnMouseDown(x,y,e); if (!clickData) return; if ((clickData.Type==2) && (e.button==0 || e.button==2)) //点击行 { if (clickData.Redraw==true) this.Draw(); } else if (clickData.Type==3 && e.button==0) //表头 { this.OnClickHeader(clickData, e); } //document.onmousemove=(e)=>{ this.DocOnMouseMove(e); } //document.onmouseup=(e)=> { this.DocOnMouseUp(e); } } this.GetTReportChart=function() { var chart=this.ChartPaint[0]; if (!chart) return null; return chart; } 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 oldMouseOnStatus=this.LastMouseStatus.MouseOnStatus; this.LastMouseStatus.OnMouseMove=null; var bShowTooltip=false; this.LastMouseStatus.TooltipStatus=null; var bShowChartTooltip=false; var chartTooltipData=null; this.LastMouseStatus.OnMouseMove={ X:x, Y:y }; var mouseStatus={ Cursor:"default", Name:"Default"};; //鼠标状态 var report=this.GetTReportChart(); var bDraw=false; if (report) { var tooltipData=report.GetTooltipData(x,y); //单元格提示信息 if (tooltipData) { if (tooltipData.Type==20) { if (tooltipData.Data && tooltipData.Data.Symbol) { bShowChartTooltip=true; chartTooltipData={ Symbol:tooltipData.Data.Symbol, Rect:tooltipData.Rect }; } } else { this.LastMouseStatus.TooltipStatus={ X:x, Y:y, Data:tooltipData, ClientX:e.clientX, ClientY:e.clientY }; bShowTooltip=true; } } } /* 目前没有用到 var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_REPORT_MOUSE_MOVE); if (event) { var sendData={X:x, Y:y, Cell:cell }; event.Callback(event,sendData,this); } */ if (mouseStatus) this.UIElement.style.cursor=mouseStatus.Cursor; if (bShowChartTooltip) { this.ShowMinuteChartTooltip(null, null, chartTooltipData); } else { this.HideMinuteChartTooltip(); } if (bShowTooltip) { var xTooltip = e.clientX-this.UIElement.getBoundingClientRect().left; var yTooltip = e.clientY-this.UIElement.getBoundingClientRect().top; this.DrawFloatTooltip({X:xTooltip, Y:yTooltip, YMove:20/pixelTatio},this.LastMouseStatus.TooltipStatus.Data); } else { this.HideFloatTooltip(); } } this.UIOnMounseOut=function(e) { this.HideMinuteChartTooltip(); } this.UIOnMouseleave=function(e) { this.HideMinuteChartTooltip(); } this.UIOnContextMenu=function(e) { e.preventDefault(); var x = e.clientX-this.UIElement.getBoundingClientRect().left; var y = e.clientY-this.UIElement.getBoundingClientRect().top; this.OnRightMenu(x,y,e); //右键菜单事件 } this.OnRightMenu=function(x,y,e) { } //点表头 this.OnClickHeader=function(clickData, e) { var header=clickData.Header; if (header.Column && header.Column.Sort==1) { var data={ CellType:header.CellType, ColumnIndex:header.ColumnIndex } this.SortHeader(header.Column, data); } } //排序 this.SortHeader=function(column, sortData) { var sortInfo={ Field:this.SortInfo.Field, Sort:this.SortInfo.Sort, CellType:this.SortInfo.CellType }; var arySortType=column.SortType; if (sortInfo.Field!=sortData.ColumnIndex || sortInfo.CellType!=sortData.CellType) { sortInfo.Field=sortData.ColumnIndex; sortInfo.CellType=sortData.CellType; sortInfo.Sort=arySortType[0] } else { if (arySortType.length==1) { sortInfo.Sort=arySortType[0]; } else { for(var i=0;i<arySortType.length;++i) { if (sortInfo.Sort==arySortType[i]) { sortInfo.Sort=arySortType[(i+1)%arySortType.length]; break; } } } } if (sortInfo.Sort==0) //还原 { this.Data.Data=[]; for(var i=0;i<this.SourceData.Data.length;++i) { this.Data.Data.push(this.SourceData.Data[i]); } } else { var event=this.GetEventCallback(JSCHART_EVENT_ID.ON_TREPORT_LOCAL_SORT); if (event && event.Callback) { var sendData={ Column:column, SortInfo:sortInfo, SymbolList:this.Data.Data, Result:null }; event.Callback (event, sendData, this); if (Array.isArray(sendData.Result)) this.Data.Data=sendData.Result; } else { this.Data.Data.sort((left, right)=> { return this.LocalSort(left, right, column, sortInfo.Sort, sortInfo.CellType); }); } } this.Data.YOffset=0; this.SortInfo.Field=sortInfo.Field; this.SortInfo.Sort=sortInfo.Sort; this.SortInfo.CellType=sortInfo.CellType; this.Draw(); this.DelayUpdateStockData(); } //本地排序 this.LocalSort=function(left, right, column, sortType, cellType) { switch(column.Type) { case TREPORT_COLUMN_ID.SYMBOL_ID: case TREPORT_COLUMN_ID.NAME_ID: return this.LocalStringSort(left, right, column, sortType, cellType); case TREPORT_COLUMN_ID.PRICE_ID: case TREPORT_COLUMN_ID.VOL_ID: case TREPORT_COLUMN_ID.UPDOWN_ID: case TREPORT_COLUMN_ID.BUY_PRICE_ID: case TREPORT_COLUMN_ID.SELL_PRICE_ID: case TREPORT_COLUMN_ID.AMOUNT_ID: case TREPORT_COLUMN_ID.BUY_VOL_ID: case TREPORT_COLUMN_ID.SELL_VOL_ID: case TREPORT_COLUMN_ID.YCLOSE_ID: case TREPORT_COLUMN_ID.OPEN_ID: case TREPORT_COLUMN_ID.HIGH_ID: case TREPORT_COLUMN_ID.LOW_ID: case TREPORT_COLUMN_ID.AVERAGE_PRICE_ID: case TREPORT_COLUMN_ID.EXE_PRICE_ID: //行权价格 case TREPORT_COLUMN_ID.POSITION_ID: //持仓量 case TREPORT_COLUMN_ID.AMPLITUDE_ID: case TREPORT_COLUMN_ID.INCREASE_ID: case TREPORT_COLUMN_ID.RESERVE_NUMBER1_ID: case TREPORT_COLUMN_ID.RESERVE_NUMBER2_ID: case TREPORT_COLUMN_ID.RESERVE_NUMBER3_ID: case TREPORT_COLUMN_ID.RESERVE_NUMBER4_ID: case TREPORT_COLUMN_ID.RESERVE_NUMBER5_ID: case TREPORT_COLUMN_ID.RESERVE_NUMBER6_ID: case TREPORT_COLUMN_ID.RESERVE_NUMBER7_ID: case TREPORT_COLUMN_ID.RESERVE_NUMBER8_ID: case TREPORT_COLUMN_ID.RESERVE_NUMBER9_ID: case TREPORT_COLUMN_ID.RESERVE_NUMBER10_ID: return this.LocalNumberSort(left, right, column, sortType, cellType); default: return 0; } } this.LocalNumberSort=function(left, right, column, sortType, cellType) { var leftStock=this.GetExePriceData(left); var rightStock=this.GetExePriceData(right); var leftValue=-99999999999999, rightValue=-99999999999999; if (sortType==2) leftValue=rightValue=99999999999999; var filedName=MAP_TREPORT_COLUMN_FIELD.get(column.Type); if (cellType==0) //行权价格 { if (leftStock && IFrameSplitOperator.IsNumber(leftStock.ExePrice)) leftValue=leftStock.ExePrice; if (rightStock && IFrameSplitOperator.IsNumber(rightStock.ExePrice)) rightValue=rightStock.ExePrice; } else if (cellType==1) { if (leftStock && leftStock.LeftData) { var value=leftStock.LeftData[filedName]; if (IFrameSplitOperator.IsNumber(value)) leftValue=value; } if (rightStock && rightStock.LeftData) { var value=rightStock.LeftData[filedName]; if (IFrameSplitOperator.IsNumber(value)) rightValue=value; } } else if (cellType==2) { if (leftStock && leftStock.RightData) { var value=leftStock.RightData[filedName]; if (IFrameSplitOperator.IsNumber(value)) leftValue=value; } if (rightStock && rightStock.RightData) { var value=rightStock.RightData[filedName] if (IFrameSplitOperator.IsNumber(value)) rightValue=value; } } if (sortType==1) { if (rightValue<leftValue) return -1; else if (rightValue<leftValue) return 1; else return 0; } else { if (leftValue<rightValue) return -1; else if (leftValue>rightValue) return 1; else return 0; } } this.OnWheel=function(e) //滚轴 { JSConsole.Chart.Log('[JSTReportChartContainer::OnWheel]',e); if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash == true) return; if (!this.Data || !IFrameSplitOperator.IsNonEmptyArray(this.Data.Data)) return; 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) return; var chart=this.GetTReportChart(); if (!chart) return; var wheelValue=e.wheelDelta; if (!IFrameSplitOperator.IsObjectExist(e.wheelDelta)) wheelValue=e.deltaY* -0.01; if (wheelValue<0) //下 { this.LastMouseStatus.TooltipStatus=null; this.HideMinuteChartTooltip(); this.HideFloatTooltip(); var result=this.MoveSelectedRow(1,{ EnablePageCycle:this.EnablePageCycle }) if (result) { if (result.Redraw) this.Draw(); if (result.Update) this.DelayUpdateStockData(); } } else if (wheelValue>0) //上 { this.LastMouseStatus.TooltipStatus=null; this.HideMinuteChartTooltip(); this.HideFloatTooltip(); var result=this.MoveSelectedRow(-1,{ EnablePageCycle:this.EnablePageCycle} ); if (result) { if (result.Redraw) this.Draw(); if (result.Update) this.DelayUpdateStockData(); } } if(e.preventDefault) e.preventDefault(); else e.returnValue = false; } this.OnKeyDown=function(e) { if (this.ChartSplashPaint && this.ChartSplashPaint.IsEnableSplash ==