hqchart
Version:
HQChart - H5, 微信小程序 沪深/港股/数字货币/期货/美股 K线图(kline),走势图,缩放,拖拽,十字光标,画图工具,截图,筹码图. 分析家语法,通达信语法,(麦语法),第3方数据对接
1,570 lines (1,285 loc) • 405 kB
JavaScript
/*
Copyright (c) 2018 jones
http://www.apache.org/licenses/LICENSE-2.0
开源项目 https://github.com/jones2000/HQChart
jones_2000@163.com
封装股票列表控件 (H5版本)
不提供内置测试数据
*/
function JSReportChart(divElement)
{
this.DivElement=divElement;
this.JSChartContainer; //表格控件
this.ResizeListener; //大小变动监听
//h5 canvas
this.CanvasElement=document.createElement("canvas");
this.CanvasElement.className='jsreportlist-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("[JSReportChart::JSReportChart] divElement hasChildNodes", divElement.childNodes);
}
divElement.appendChild(this.CanvasElement);
//额外的画布
this.MapExtraCanvasElement=new Map(); //key=画布名字, value={ Element:, Canvas:}
this.CreateExtraCanvasElement=function(name, option)
{
if (this.MapExtraCanvasElement.has(name)) return this.MapExtraCanvasElement.get(name);
var element=document.createElement("canvas");
element.className='jsreportlist-drawing-extra';
element.id=Guid();
if (name==JSReportChart.CorssCursorCanvasKey)
element.setAttribute("tabindex",5);
else
element.setAttribute("tabindex",1);
if (element.style)
{
element.style.outline='none';
element.style.position="absolute";
element.style.left='0px';
element.style.top='0px';
element.style["pointer-events"]="none";
}
if (option)
{
if (IFrameSplitOperator.IsNumber(option.TabIndex)) element.setAttribute("tabindex",option.TabIndex);
if (IFrameSplitOperator.IsNumber(option.ZIndex)) element.style["z-index"]=option.ZIndex;
}
if (this.CanvasElement)
{
element.height=this.CanvasElement.height;
element.width=this.CanvasElement.width;
if (element.style)
{
element.style.width=this.CanvasElement.style.width;
element.style.height=this.CanvasElement.style.height
}
}
divElement.appendChild(element);
var item={ Element:element, Canvas:null };
this.MapExtraCanvasElement.set(name, item);
}
this.GetExtraCanvas=function(name)
{
if (!this.MapExtraCanvasElement.has(name)) return null;
var item=this.MapExtraCanvasElement.get(name);
if (!item.Element) return null;
if (!item.Canvas) item.Canvas=item.Element.getContext("2d");
return item;
}
this.OnSize=function()
{
//画布大小通过div获取
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;
//扩展画布
for(var mapItem of this.MapExtraCanvasElement)
{
var item=mapItem[1];
var element=item.Element;
if (!element) continue;
element.height=this.CanvasElement.height;
element.width=this.CanvasElement.width;
element.style.width=this.CanvasElement.style.width;
element.style.height=this.CanvasElement.style.height;
}
JSConsole.Chart.Log(`[JSReportChart::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.CreateJSReportChartContainer(option);
if (!chart) return false;
if (option.OnCreatedCallback) option.OnCreatedCallback(chart);
this.JSChartContainer=chart;
this.DivElement.JSChart=this; //div中保存一份
//注册事件
if (option.EventCallback)
{
for(var i=0;i<option.EventCallback.length;++i)
{
var item=option.EventCallback[i];
chart.AddEventCallback(item);
}
}
if (option.EnableResize==true) this.CreateResizeListener();
if (option.EnablePopMenuV2===true) chart.InitalPopMenu();
if (option.FloatTooltip && option.FloatTooltip.Enable) chart.InitalFloatTooltip(option.FloatTooltip); //提示信息
if (option.MinuteChartTooltip && option.MinuteChartTooltip.Enable) chart.InitalMinuteChartTooltip(option.MinuteChartTooltip);
if (option.KLineChartTooltip && option.KLineChartTooltip.Enable) chart.InitalKLineChartTooltip(option.KLineChartTooltip);
if (option.Symbol) chart.Symbol=option.Symbol;
if (option.Name) chart.Name=option.Name;
var requestOption={ Callback:null };
if (chart.Symbol) requestOption.Callback=function(){ chart.RequestMemberListData(); };
if (option.LoadStockList===false)
{
chart.ChartSplashPaint.IsEnableSplash=false;
chart.Draw();
}
else
{
chart.RequestStockListData(requestOption); //下载码表
}
}
this.CreateJSReportChartContainer=function(option)
{
var chart=new JSReportChartContainer(this.CanvasElement);
chart.GetExtraCanvas=(name)=>{ return this.GetExtraCanvas(name); }
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.IsNumber(option.WheelPageType)) chart.WheelPageConfig.Type=option.WheelPageType;
if (IFrameSplitOperator.IsBool(option.PageUpDownCycle)) chart.PageUpDownCycle=option.PageUpDownCycle;
if (IFrameSplitOperator.IsBool(option.EnablePageUpdate)) chart.EnablePageUpdate=option.EnablePageUpdate;
if (option.WheelPage)
{
var item=option.WheelPage;
if (IFrameSplitOperator.IsNumber(item.Type)) chart.WheelPageConfig.Type=item.Type;
if (IFrameSplitOperator.IsPlusNumber(item.RowStep)) chart.WheelPageConfig.RowStep=item.RowStep;
if (IFrameSplitOperator.IsBool(item.EnableCtrlTurn)) chart.WheelPageConfig.EnableCtrlTurn=item.EnableCtrlTurn;
}
//数据下载提示信息
if (IFrameSplitOperator.IsObject(option.SplashTitle))
{
var item=option.SplashTitle;
if (item) chart.SplashTitle.StockList=item.StockList;
if (item) chart.SplashTitle.MemberList=item.MemberList;
}
if (option.VScrollbar) chart.SetVScrollbar(option.VScrollbar);
if (option.SortInfo)
{
var item=option.SortInfo;
if (item.Search) chart.SortInfo.Field=chart.FindFiledIndex(item.Search);
if (IFrameSplitOperator.IsNumber(item.Field)) chart.SortInfo.Field=item.Field;
if (IFrameSplitOperator.IsNumber(item.Sort)) chart.SortInfo.Sort=item.Sort;
}
if (option.VirtualTable)
{
var item=option.VirtualTable;
if (IFrameSplitOperator.IsBool(item.Enable)) chart.Data.Virtual.Enable=item.Enable;
}
var reportChart=chart.GetReportChart();
if (reportChart)
{
if (IFrameSplitOperator.IsNumber(option.TextOverflowStyle)) reportChart.TextOverflowStyle=option.TextOverflowStyle;
if (IFrameSplitOperator.IsNumber(option.MultiSelectModel)) reportChart.MultiSelectModel=option.MultiSelectModel;
if (IFrameSplitOperator.IsNumber(option.SelectedStyle)) reportChart.SelectedStyle=option.SelectedStyle;
if (option.BottomTab)
{
var item=option.BottomTab;
if (IFrameSplitOperator.IsBool(item.IsShow)) reportChart.Tab.IsShow=item.IsShow;
}
}
this.SetChartBorder(chart, option);
//是否自动更新
if (option.IsAutoUpdate!=null) chart.IsAutoUpdate=option.IsAutoUpdate;
if (option.AutoUpdateFrequency>0) chart.AutoUpdateFrequency=option.AutoUpdateFrequency;
//数据筛选
if (option.DataFilter)
{
var item=option.DataFilter;
if (IFrameSplitOperator.IsBool(item.Enable)) chart.DataFilterConfig.Enable=item.Enable;
}
//注册事件
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("[JSReportChart::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.SetSelectedRow=function(option)
{
if (this.JSChartContainer) this.JSChartContainer.SetSelectedRow(option);
}
this.DeleteSymbol=function(arySymbol, option)
{
if (this.JSChartContainer) this.JSChartContainer.DeleteSymbol(arySymbol, option);
}
this.AddSymbol=function(arySymbol, option)
{
if (this.JSChartContainer) this.JSChartContainer.AddSymbol(arySymbol, option);
}
this.EnableDataFilter=function(bEnable, option) //启动|关闭筛选
{
if (this.JSChartContainer) this.JSChartContainer.EnableDataFilter(bEnable, option);
}
//事件回调
this.AddEventCallback=function(obj)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.AddEventCallback)=='function')
{
JSConsole.Chart.Log('[JSReportChart:AddEventCallback] obj=', obj);
this.JSChartContainer.AddEventCallback(obj);
}
}
//重新加载配置
this.ReloadResource=function(option)
{
if(this.JSChartContainer && typeof(this.JSChartContainer.ReloadResource)=='function')
{
JSConsole.Chart.Log('[JSReportChart: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('[JSReportChart:Draw] ');
this.JSChartContainer.Draw();
}
}
}
JSReportChart.Init=function(divElement)
{
var jsChartControl=new JSReportChart(divElement);
jsChartControl.OnSize();
return jsChartControl;
}
//自定义风格
JSReportChart.SetStyle=function(option)
{
if (option) g_JSChartResource.SetStyle(option);
}
//获取颜色配置 (设置配必须啊在JSChart.Init()之前)
JSReportChart.GetResource=function()
{
return g_JSChartResource;
}
function HQReportItem()
{
this.OriginalSymbol; //原始代码
this.Symbol;
this.Name;
this.YClose;
this.Open;
this.Price;
this.High;
this.Low;
this.Amount;
this.Vol;
this.Increase; //涨幅
this.UpDown; //涨跌
this.Exchange; //换手
this.Amplitude; //振幅
this.BuyPrice; //买价/量
this.BuyVol;
this.SellPrice; //卖价/量
this.SellVol;
this.AvPrice; //均价
this.LimitHigh; //涨停价
this.LimitLow; //跌停价
this.VolIn; //内盘
this.VolOut; //外盘
this.DealNum; //现量
this.OutShares; //流通股本
this.TotalShares; //总股本
this.MarketValue; //总市值
this.CircMarketValue;//流通市值
this.CloseLine; //{Data:[], Max:, Min:, Count: }
this.ExtendData; //扩展数据
this.Time;
this.Date;
}
function JSReportChartContainer(uielement)
{
this.ClassName='JSReportChartContainer';
this.Frame; //框架画法
this.ChartPaint=[]; //图形画法
this.ChartSplashPaint=null; //等待提示
this.LoadDataSplashTitle="数据加载中"; //下载数据提示信息
this.SplashTitle={ StockList:"下载码表中.....", MemberList:"下载成分中....." } ;
this.Canvas=uielement.getContext("2d"); //画布
this.Symbol; //板块代码
this.Name; //板块名称
this.NetworkFilter; //数据回调接口
this.Data={ XOffset:0, YOffset:0, Data:[], Virtual:{ Enable:false, Count:0 } }; //股票列表 (Virtual 虚拟表)
this.SourceData={ Data:[] } ; //原始股票顺序(排序还原用)
this.BlockData=new Map(); //当前板块数据
this.MapStockData=new Map(); //原始股票数据
this.FixedRowData={ Data:[], Type:0, Symbol:[] }; //顶部固定行Data:[{ Value:, Text:, Color:, TextAgiln: }], Type:0=自定义数据, 1 =(股票数据) Symbol:[],
this.FlashBG=new Map();
this.FlashBGTimer=null; //闪烁背景 Value:{ LastTime:数据最后的时间, Data: { Key:ID, BGColor:, Time: , Count: 次数 } };
this.GlobalOption={ FlashBGCount:0 };
//this.FixedRowData.Data=[ [null, {Value:11, Text:"11" }], [null, null, null, {Value:12, Text:"ddddd", Color:"rgb(45,200,4)"}]];
this.SortInfo={ Field:-1, Sort:0 }; //排序信息 {Field:排序字段id, Sort:0 不排序 1升序 2降序 }
//行拖拽
this.DragRow;
this.DragColumnWidth; //列宽拖动
this.EnableDragRow=false;
this.DragRowType=0; //0=插入 1=交换
this.AutoDragScrollTimer=null;
this.EnablePageScroll=false;
this.DragMove; //={ Click:{ 点击的点}, Move:{最后移动的点}, PreMove:{上一个点的位置} };
//表头拖拽
this.DragHeader;
this.EnableDragHeader=false;
//事件回调
this.mapEvent=new Map(); //通知外部调用 key:JSCHART_EVENT_ID value:{Callback:回调,}
this.AutoUpdateTimer=null;
this.AutoUpdateFrequency=15000; //15秒更新一次数据
this.EnablePageUpdate=true; //当前页更新模式 ture=翻页都请求数据 false=所有页的数据一次下载完成
this.DelayUpdateTimer=null; //延迟更新
this.DelayUpdateFrequency=500; //延迟更新时间
this.UIElement=uielement;
this.LastPoint=new Point(); //鼠标位置
this.IsOnTouch=false;
this.TouchDrag;
this.TouchMoveMinAngle=70; //左右移动最小角度
this.YStepPixel=5*GetDevicePixelRatio();
this.XStepPixel=10*GetDevicePixelRatio();
this.PageUpDownCycle=true; //翻页循环
this.DragPageCycle=true; //手机翻页循环
//this.WheelPageType=0; //鼠标滚轴翻页模式 0=一页一页翻 1=一条一条翻
//鼠标滚轴配置
// Type:0=一页一页翻 1=一条一条翻,
// RowStep:单条数据滚动步长
// EnableCtrlTurn Ctrl+滚轴翻页
this.WheelPageConfig={ Type:0, RowStep:1, EnableCtrlTurn:false }
//拖拽滚动条
this.DragXScroll=null; //{Start:{x,y}, End:{x, y}}
this.DragYScroll=null;
this.IsShowVScrollbar=false;
this.IsDestroy=false; //是否已经销毁了
this.JSPopMenu; //内置菜单
this.IsShowRightMenu=true;
//
this.TooltipMinuteChart; //分时图
this.TooltipKLineChart; //分时图
this.FloatTooltip; //提示浮框
//MouseOnStatus:{ RowIndex:行, ColumnIndex:列}
this.LastMouseStatus={ MoveStatus:null, TooltipStatus:null, MouseOnStatus:null };
this.RequestStatus={ IsFinishStockList:false, IsFinishMemberList:false }; //下载状态
this.DataFilterConfig={ Enable:false, }; //数据筛选
this.ChartDestroy=function() //销毁
{
this.IsDestroy=true;
this.StopAutoUpdate();
this.DestroyMinuteChartTooltip();
this.DestroyKLineChartTooltip();
this.DestroyFloatTooltip();
}
this.StopAutoDragScrollTimer=function()
{
JSConsole.Chart.Log("[JSReportChartContainer::StopAutoDragScrollTimer] stop ");
this.EnablePageScroll=false;
if (this.AutoDragScrollTimer!=null)
{
clearTimeout(this.AutoDragScrollTimer);
this.AutoDragScrollTimer = null;
}
}
this.InitalPopMenu=function() //初始化弹出窗口
{
if (this.JSPopMenu) return;
this.JSPopMenu=new JSPopMenu(); //内置菜单
this.JSPopMenu.Inital();
}
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;
}
this.InitalKLineChartTooltip=function(option)
{
if (this.TooltipKLineChart) return;
this.TooltipKLineChart=new JSTooltipKLineChart();
this.TooltipKLineChart.Inital(this, option);
this.TooltipKLineChart.Create();
}
this.DestroyKLineChartTooltip=function()
{
if (!this.TooltipKLineChart) return;
this.TooltipKLineChart.Destroy();
this.TooltipKLineChart=null;
}
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:3,
};
this.FloatTooltip.Update(sendData);
}
//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.ShowKLineChartTooltip=function(x,y, data)
{
if (!this.TooltipKLineChart) 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.TooltipKLineChart.Show(data, x,y);
}
this.HideKLineChartTooltip=function()
{
if (!this.TooltipKLineChart) return;
this.TooltipKLineChart.Hide();
}
this.HideAllTooltip=function()
{
this.HideKLineChartTooltip();
this.HideMinuteChartTooltip();
this.HideFloatTooltip();
}
this.AutoScrollPage=function(step)
{
this.AutoDragScrollTimer=setTimeout(() =>
{
this.ChartOperator_Temp_ScrollPage(step);
},300);
}
this.ChartOperator_Temp_ScrollPage=function(moveSetp)
{
if (!this.EnablePageScroll) return;
var reportChart=this.GetReportChart()
if (!reportChart) return;
if (moveSetp>0)
{
var pageStatus=reportChart.GetCurrentPageStatus();
if (pageStatus.IsEnd) return;
this.MoveYOffset(moveSetp, false);
++moveSetp;
}
else if (moveSetp<0)
{
if (this.Data.YOffset<=0) return;
this.MoveYOffset(moveSetp, false);
--moveSetp;
}
else
{
return;
}
this.Draw();
if (!this.EnablePageScroll) return;
this.AutoScrollPage(moveSetp);
return;
}
//清空画布
this.ClearCanvas=function(canvas)
{
if (!canvas) return;
if (!this.UIElement) return;
canvas.clearRect(0,0,this.UIElement.width,this.UIElement.height);
}
//清空固定行数据
this.ClearFixedRowData=function()
{
this.FixedRowData.Data=[];
this.FixedRowData.Symbol=[];
}
//设置固定行
this.SetFixedRowCount=function(value)
{
var chart=this.GetReportChart();
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 JSReportFrame();
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 ChartReport();
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.GetStockDataCallback=(symbol)=>{ return this.GetStockData(symbol);}
chart.GetBlockDataCallback=(symbol)=>{ return this.GetBlockData(symbol);}
chart.GetFlashBGDataCallback=(symbol, time)=>{ return this.GetFlashBGData(symbol, time); }
chart.Data=this.Data;
chart.GlobalOption=this.GlobalOption;
chart.FixedRowData=this.FixedRowData;
chart.SortInfo=this.SortInfo;
chart.Tab=new ChartReportTab();
chart.Tab.Frame=this.Frame;
chart.Tab.Canvas=this.Canvas;
chart.Tab.ChartBorder=this.Frame.ChartBorder;
chart.Tab.Report=chart;
chart.VScrollbar=new ChartVScrollbar();
chart.VScrollbar.Frame=this.Frame;
chart.VScrollbar.Canvas=this.Canvas;
chart.VScrollbar.ChartBorder=this.Frame.ChartBorder;
chart.VScrollbar.Report=chart;
chart.VScrollbar.IsShowCallback=()=>
{
if (this.DragYScroll) return true;
return this.IsShowVScrollbar;
}
this.ChartPaint[0]=chart;
//页脚
if (option && option.PageInfo===true)
{
var pageInfoChart=new ChartReportPageInfo();
pageInfoChart.Frame=this.Frame;
pageInfoChart.ChartBorder=this.Frame.ChartBorder;
pageInfoChart.Canvas=this.Canvas;
pageInfoChart.Report=chart;
this.ChartPaint[1]=pageInfoChart;
}
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.TabShow)) chart.Tab.IsShow=option.TabShow;
if (IFrameSplitOperator.IsNumber(option.FixedRowCount)) chart.FixedRowCount=option.FixedRowCount; //固定行
if (IFrameSplitOperator.IsNumber(option.SelectedModel)) chart.SelectedModel=option.SelectedModel;
if (IFrameSplitOperator.IsNumber(option.HeaderRowCount)) chart.HeaderRowCount=option.HeaderRowCount;
if (IFrameSplitOperator.IsNonEmptyArray(option.FixedSymbol))
{
chart.FixedRowCount=0;
this.FixedRowData.Type=1;
this.FixedRowData.Symbol=[];
var aryData=option.FixedSymbol;
for(var i=0; i<aryData.length; ++i)
{
var item=aryData[i];
this.FixedRowData.Symbol.push(item.Symbol);
++chart.FixedRowCount;
}
}
if (option.CellBorder)
{
var item=option.CellBorder;
if (IFrameSplitOperator.IsBool(item.IsShowVLine)) chart.CellBorderConfig.IsShowVLine=item.IsShowVLine;
if (IFrameSplitOperator.IsBool(item.IsShowHLine)) chart.CellBorderConfig.IsShowHLine=item.IsShowHLine;
if (IFrameSplitOperator.IsBool(item.IsFullLine)) chart.CellBorderConfig.IsFullLine=item.IsFullLine;
}
}
var bRegisterKeydown=true;
var bRegisterWheel=true;
if (option)
{
if (option.KeyDown===false)
{
bRegisterKeydown=false;
JSConsole.Chart.Log('[JSDealChartContainer::Create] not register keydown event.');
}
if (option.Wheel===false)
{
bRegisterWheel=false;
JSConsole.Chart.Log('[JSDealChartContainer::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.onmouseup=(e)=>{ this.UIOnMounseUp(e); }
this.UIElement.oncontextmenu=(e)=> { this.UIOnContextMenu(e); }
this.UIElement.onmousemove=(e)=>{ this.UIOnMouseMove(e);}
this.UIElement.onmouseout=(e)=>{ this.UIOnMounseOut(e); }
this.UIElement.onmouseleave=(e)=>{ this.UIOnMouseleave(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(this.LastMouseStatus);
}
for(var i=0; i<this.ChartPaint.length; ++i)
{
var item=this.ChartPaint[i];
if (!item.IsDrawFirst)
item.Draw(this.LastMouseStatus);
}
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.ResetReportStatus=function()
{
this.Data.XOffset=0;
this.Data.YOffset=0;
}
this.ResetReportSelectStatus=function()
{
var chart=this.GetReportChart();
if (chart)
{
chart.SelectedRow=-1;
chart.SelectedFixedRow=-1;
chart.MultiSelectedRow=[];
}
}
this.ClearData=function()
{
this.SourceData.Data=[];
this.Data.Data=[];
this.Data.Virtual.Count=0;
this.BlockData=new Map();
}
this.ClearMapStockData=function()
{
this.MapStockData=new Map();
}
this.ResetSortStatus=function()
{
this.SortInfo.Field=-1;
this.SortInfo.Sort=0;
}
this.SetSelectedRow=function(option)
{
var reportChart=this.GetReportChart();
if (!reportChart) return false;
if (!reportChart.SetSelectedRow(option)) return false;
this.Draw();
}
//设置股票列表
this.SetSymbolList=function(arySymbol, option)
{
this.ClearData();
this.ResetReportStatus();
this.ResetSortStatus();
if (IFrameSplitOperator.IsNonEmptyArray(arySymbol))
{
for(var i=0;i<arySymbol.length;++i)
{
this.Data.Data.push(arySymbol[i]);
}
}
var chart=this.ChartPaint[0];
if (chart) chart.Data=this.Data;
this.Draw();
}
this.ChangeSymbol=function(symbol, option)
{
this.Symbol=symbol;
this.ClearData();
this.ResetReportStatus();
this.ResetSortStatus();
this.ResetReportSelectStatus();
if (option)
{
if (IFrameSplitOperator.IsNumber(option.TabSelected))
{
var chartTab=this.GetTabChart();
if (chartTab) chartTab.SelectedTabIndex=option.TabSelected;
}
if (Array.isArray(option.FixedSymbol))
{
var chart=this.GetReportChart();
if (chart)
{
chart.FixedRowCount=0;
this.FixedRowData.Type=1;
this.FixedRowData.Symbol=[];
var aryData=option.FixedSymbol;
for(var i=0; i<aryData.length; ++i)
{
var item=aryData[i];
this.FixedRowData.Symbol.push(item.Symbol);
++chart.FixedRowCount;
}
this.SetSizeChange(true);
}
}
if (option.SortInfo)
{
var item=option.SortInfo;
if (item.Search) this.SortInfo.Field=this.FindFiledIndex(item.Search);
if (IFrameSplitOperator.IsNumber(item.Field)) this.SortInfo.Field=item.Field;
if (IFrameSplitOperator.IsNumber(item.Sort)) this.SortInfo.Sort=item.Sort;
}
if (IFrameSplitOperator.IsNonEmptyArray(option.Column)) //字段重新设置
{
this.SetColumn(option.Column, { Draw:false })
}
if (IFrameSplitOperator.IsBool(option.IsReloadStockList) && option.IsReloadStockList)
{
var requestOption={ Callback:null };
if (this.Symbol) requestOption.Callback=()=>{ this.RequestMemberListData(); };
this.MapStockData=new Map();
this.RequestStatus.IsFinishStockList=false;
this.RequestStatus.IsFinishMemberList=false;
this.RequestStockListData(requestOption);
return;
}
}
this.RequestMemberListData();
}
//更新数据 option={ SortInfo:{ Search:, Field:, Sort: } }
this.UpdateFullData=function(data, option)
{
var arySymbol=[];
if (IFrameSplitOperator.IsNonEmptyArray(data.data))
{
//0=证券代码 1=股票名称
for(var i=0;i<data.data.length;++i)
{
var item=data.data[i];
var symbol=item[0];
var stock=null;
if (this.MapStockData.has(symbol))
{
stock=this.MapStockData.get(symbol);
}
else
{
stock=new HQReportItem();
stock.OriginalSymbol=symbol;
this.MapStockData.set(symbol, stock);
}
stock.Symbol=this.GetSymbolNoSuffix(symbol);
stock.Name=item[1];
this.ReadStockJsonData(stock, item);
arySymbol.push(symbol);
}
}
//设置显示数据
this.Data.Data=[];
this.SourceData.Data=[];
if (IFrameSplitOperator.IsNonEmptyArray(arySymbol))
{
for(var i=0;i<arySymbol.length;++i)
{
this.Data.Data.push(arySymbol[i]);
this.SourceData.Data.push(arySymbol[i]);
}
}
if (option && option.SortInfo)
{
//本地排序
var item=option.SortInfo;
if (item.Search) this.SortInfo.Field=this.FindFiledIndex(item.Search);
if (IFrameSplitOperator.IsNumber(item.Field)) this.SortInfo.Field=item.Field;
if (IFrameSplitOperator.IsNumber(item.Sort)) this.SortInfo.Sort=item.Sort;
}
//排序
var chart=this.GetReportChart();
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];
this.LocalDataSort(column, this.SortInfo);
}
this.Draw();
}
//设置全部的数据
this.SetFullData=function(data, option)
{
this.ClearMapStockData();
this.ClearData();
this.ResetReportStatus();
this.ResetSortStatus();
this.ResetReportSelectStatus();
this.UpdateFullData(data, option);
/*
//缓存所有数据
var arySymbol=[];
if (IFrameSplitOperator.IsNonEmptyArray(data.data))
{
//0=证券代码 1=股票名称
for(var i=0;i<data.data.length;++i)
{
var item=data.data[i];
var symbol=item[0];
var stock=null;
if (this.MapStockData.has(symbol))
{
stock=this.MapStockData.get(symbol);
}
else
{
stock=new HQReportItem();
stock.OriginalSymbol=symbol;
this.MapStockData.set(symbol, stock);
}
stock.Symbol=this.GetSymbolNoSuffix(symbol);
stock.Name=item[1];
this.ReadStockJsonData(stock, item);
arySymbol.push(symbol);
}
}
//设置显示数据
if (IFrameSplitOperator.IsNonEmptyArray(arySymbol))
{
for(var i=0;i<arySymbol.length;++i)
{
this.Data.Data.push(arySymbol[i]);
this.SourceData.Data.push(arySymbol[i]);
}
}
this.Draw();
*/
}
this.RequestMemberListData=function()
{
if (this.RequestStatus.IsFinishStockList==false) return; //码表没有下完
//this.ChartSplashPaint.SetTitle(this.SplashTitle.MemberList);
//this.ChartSplashPaint.EnableSplash(true);
//this.Draw();
this.RequestStatus.IsFinishMemberList=false;
var self=this;
if (this.NetworkFilter)
{
var obj=
{
Name:'JSReportChartContainer::RequestMemberListData', //类名::
Explain:'板块成分数据',
Request:{ Data: { symbol: this.Symbol } },
Self:this,
PreventDefault:false
};
if (this.SortInfo.Field>=0 && this.SortInfo.Sort>0)
{
var reportChart=this.GetReportChart();
if (reportChart)
{
var column=reportChart.Column[this.SortInfo.Field];
obj.Sort={ Column:column, Field:this.SortInfo.Field, Sort:this.SortInfo.Sort} ;
}
}
this.NetworkFilter(obj, function(data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvMemberListData(data);
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
//throw { Name:'JSReportChartContainer::RequestMemberListData', Error:'(板块成分数据)不提供内置测试数据' };
}
this.RecvMemberListData=function(recvData)
{
this.ClearData();
if (IFrameSplitOperator.IsNonEmptyArray(recvData.data))
{
for(var i=0;i<recvData.data.length;++i)
{
this.Data.Data.push(recvData.data[i]);
this.SourceData.Data.push(recvData.data[i]);
}
}
if (recvData.Virtual) //虚拟表设置
{
var item=recvData.Virtual;
if (IFrameSplitOperator.IsNumber(item.Count)) this.Data.Virtual.Count=item.Count;
}
this.RequestStatus.IsFinishMemberList=true;
this.DataFilter();
//实时本地数据排序
var chart=this.GetReportChart();
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];
this.LocalDataSort(column, this.SortInfo);
}
this.Draw();
this.UpdateStockData();
}
//删除股票
this.DeleteSymbol=function(arySymbol, option)
{
if (!IFrameSplitOperator.IsNonEmptyArray(arySymbol)) return false;
var setSymbol=new Set(arySymbol);
var bFinder=false;
if (IFrameSplitOperator.IsNonEmptyArray(this.SourceData.Data))
{
var aryData=[];
for(var i=0;i<this.SourceData.Data.length;++i)
{
var item=this.SourceData.Data[i];
if (setSymbol.has(item))
{
bFinder=true;
continue;
}
aryData.push(item);
}
if (bFinder) this.SourceData.Data=aryData;
}
if (IFrameSplitOperator.IsNonEmptyArray(this.Data.Data))
{
var aryData=[];
for(var i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
if (setSymbol.has(item))
{
bFinder=true;
continue;
}
aryData.push(item);
}
if (bFinder) this.Data.Data=aryData;
}
if (!bFinder) return false;
this.Draw();
this.UpdateStockData();
return true;
}
//添加股票
this.AddSymbol=function(arySymbol, option)
{
if (!IFrameSplitOperator.IsNonEmptyArray(arySymbol)) return false;
var bDuplicate=true;
if (option && IFrameSplitOperator.IsBool(option.Duplicate)) bDuplicate=option.Duplicate; //是否去重
var mapSymbol=new Map();
for(var i=0;i<arySymbol.length;++i)
{
var item={ Symbol:arySymbol[i], IsExist:false, IsExist2:false };
mapSymbol.set(item.Symbol, item);
}
if (bDuplicate)
{
if (IFrameSplitOperator.IsNonEmptyArray(this.SourceData.Data))
{
for(var i=0;i<this.SourceData.Data.length;++i)
{
var item=this.Data.Data[i];
if (mapSymbol.has(item))
{
mapSymbol.get(item).IsExist=true;
}
}
}
if (IFrameSplitOperator.IsNonEmptyArray(this.Data.Data))
{
for(var i=0;i<this.Data.Data.length;++i)
{
var item=this.Data.Data[i];
if (mapSymbol.has(item))
{
mapSymbol.get(item).IsExist2=true;
}
}
}
}
for(var mapItem of mapSymbol)
{
var item=mapItem[1];
if (!item.IsExist) this.SourceData.Data.push(item.Symbol);
if (!item.IsExist2) this.Data.Data.push(item.Symbol);
}
this.Draw();
this.UpdateStockData();
return true;
}
//下载码表
this.RequestStockListData=function(option)
{
this.RequestStatus.IsFinishStockList=false;
this.ChartSplashPaint.SetTitle(this.SplashTitle.StockList);
this.ChartSplashPaint.EnableSplash(true);
this.Draw();
var self=this;
if (this.NetworkFilter)
{
var obj=
{
Name:'JSReportChartContainer::RequestStockListData', //类名::
Explain:'码表数据',
Self:this,
PreventDefault:false
};
this.NetworkFilter(obj, function(data)
{
self.ChartSplashPaint.EnableSplash(false);
self.RecvStockListData(data,option);
});
if (obj.PreventDefault==true) return; //已被上层替换,不调用默认的网络请求
}
//throw { Name:'JSReportChartContainer::RequestStockListData', Error:'(码表数据)不提供内置测试数据' };
}
this.RecvStockListData=function(data, option)
{
if (IFrameSplitOperator.IsNonEmptyArray(data.data))
{
//0=证券代码 1=股票名称
for(var i=0;i<data.data.length;++i)
{
var item=data.data[i];
var symbol=item[0];
var stock=null;
if (this.MapStockData.has(symbol))
{
stock=this.MapStockData.get(symbol);
}
else
{
stock=new HQReportItem();
stock.OriginalSymbol=symbol;
this.MapStockData.set(symbol, stock);
}
stock.Symbol=this.GetSymbolNoSuffix(symbol);
stock.Name=item[1];
if (IFrameSplitOperator.IsNumber(item[88])) stock.PriceColorType=item[88];
this.ReadStockJsonData(stock, item);
}
}
this.RequestStatus.IsFinishStockList=true;
if (option && option.Callback)
{
option.Callback();
return;
}
this.Draw();
this.UpdateStockData();
}
//更新股票数据
this.UpdateMapStockData=function(data)
{
if (!data || !IFrameSplitOperator.IsNonEmptyArray(data.data)) return;
//0=证券代码 1=股票名称
for(var i=0;i<data.data.length;++i)
{
var item=data.data[i];
var symbol=item[0];
var stock=null;
if (this.MapStockData.has(symbol))
{
stock=this.MapStockData.get(symbol);
}
else
{
stock=new HQReportItem();
stock.OriginalSymbol=symbol;
this.MapStockData.set(symbol, stock);
}
stock.Symbol=this.GetSymbolNoSuffix(symbol);
stock.Name=item[1];
this.ReadStockJsonData(stock, item);
}
}
//获取个股数据
this.GetStockData=function(symbol)
{
if (!this.MapStockData) return null;
if (!this.MapStockData.has(symbol)) return null;
return this.MapStockData.get(symbol);
}
this.GetBlockData=function(symbol)
{
if (!this.BlockData) return null;
if (!this.BlockData.has(symbol)) return null;
return this.BlockData.get(symbol);
}
//obj={ ID:, Color: , Time:, Count: }
this.SetFlashBGItem=function(symbol, obj)
{
var item={ ID:obj.ID, Color:obj.Color, Count:1 };
if (IFrameSplitOperator.IsNumber(obj.Count)) item.Count=obj.Count;
if (IFrameSplitOperator.IsNumber(obj.Time)) item.Time=obj.Time;
else item.Time=Date.now();
if (this.FlashBG.has(symbol))
{
var stockItem=this.FlashBG.get(symbol);
stockItem.LastTime=item.Time;
stockItem.Data.set(item.ID, item);
}
else
{
var stockItem={ LastTime:item.Time, Data:new Map([ [item.ID, item ] ]) };
this.FlashBG.set(symbol, stockItem);
}
}
this.GetFlashBGData=function(symbol, time)
{
if (!this.FlashBG) return null;
if (!this.FlashBG.has(symbol)) return null;
var timeDiff=3*1000;
var stockItem=this.FlashBG.get(symbol);
if (time-stockItem.LastTime>=timeDiff) //超时的删除
{
this.FlashBG.delete(symbol);
return null;
}
if (!stockItem.Data || stockItem.Data.size<=0)
{
this.FlashBG.delete(symbol);
return null;
}
var aryDelID=[]; //超时需要参数的
for(var mapItem of stockItem.Data)
{
var item=mapItem[1];
if (time-item.Time>=timeDiff || item.Count<=0)
aryDelID.push(item.ID);
}
if (IFrameSplitOperator.IsNonEmptyArray(aryDelID))
{
for(var i=0; i<aryDelID.length; ++i)
{
stockItem.Data.delete(aryDelID[i]);
}
if (stockItem.Data.size<=0)
{
this.FlashBG.delete(symbol);
return null;
}
}
return stockItem;
}
//delay=是否延迟
this.DelayUpdateStockData=function()
{